summaryrefslogtreecommitdiff
path: root/test/engine
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2019-08-02 12:34:16 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2019-08-06 18:05:45 -0400
commit00b5c10846e800304caa86549ab9da373b42fa5d (patch)
tree0832401deebeaad5fd6edc99158d0b10f958e716 /test/engine
parente091775f1c4c817093e9a936a3abc79b5e311f93 (diff)
downloadsqlalchemy-00b5c10846e800304caa86549ab9da373b42fa5d.tar.gz
Modernize internal reflection
- Deprecated remaining engine-level introspection and utility methods including :meth:`.Engine.run_callable`, :meth:`.Engine.transaction`, :meth:`.Engine.table_names`, :meth:`.Engine.has_table`. The utility methods are superseded by modern context-manager patterns, and the table introspection tasks are suited by the :class:`.Inspector` object. - The internal dialect method ``Dialect.reflecttable`` has been removed. A review of third party dialects has not found any making use of this method, as it was already documented as one that should not be used by external dialects. Additionally, the private ``Engine._run_visitor`` method is also removed. - The long-deprecated ``Inspector.get_table_names.order_by`` parameter has been removed. - The :paramref:`.Table.autoload_with` parameter now accepts an :class:`.Inspector` object directly, as well as any :class:`.Engine` or :class:`.Connection` as was the case before. Fixes: #4755 Change-Id: Iec3a8b0f3e298ba87d532b16fac1e1132f464e21
Diffstat (limited to 'test/engine')
-rw-r--r--test/engine/test_bind.py13
-rw-r--r--test/engine/test_deprecations.py250
-rw-r--r--test/engine/test_execute.py41
-rw-r--r--test/engine/test_reflection.py87
-rw-r--r--test/engine/test_transaction.py20
5 files changed, 282 insertions, 129 deletions
diff --git a/test/engine/test_bind.py b/test/engine/test_bind.py
index ac209c69b..39acfed2c 100644
--- a/test/engine/test_bind.py
+++ b/test/engine/test_bind.py
@@ -4,6 +4,7 @@ including the deprecated versions of these arguments"""
import sqlalchemy as sa
from sqlalchemy import engine
from sqlalchemy import exc
+from sqlalchemy import inspect
from sqlalchemy import Integer
from sqlalchemy import MetaData
from sqlalchemy import testing
@@ -12,6 +13,8 @@ from sqlalchemy import ThreadLocalMetaData
from sqlalchemy.testing import assert_raises
from sqlalchemy.testing import assert_raises_message
from sqlalchemy.testing import fixtures
+from sqlalchemy.testing import is_false
+from sqlalchemy.testing import is_true
from sqlalchemy.testing.schema import Column
from sqlalchemy.testing.schema import Table
@@ -37,11 +40,11 @@ class BindTest(fixtures.TestBase):
for bind in (testing.db, testing.db.connect()):
for args in [([], {"bind": bind}), ([bind], {})]:
metadata.create_all(*args[0], **args[1])
- assert table.exists(*args[0], **args[1])
+ is_true(inspect(bind).has_table(table.name))
metadata.drop_all(*args[0], **args[1])
table.create(*args[0], **args[1])
table.drop(*args[0], **args[1])
- assert not table.exists(*args[0], **args[1])
+ is_false(inspect(bind).has_table(table.name))
def test_create_drop_err_metadata(self):
metadata = MetaData()
@@ -57,7 +60,7 @@ class BindTest(fixtures.TestBase):
metadata = MetaData()
table = Table("test_table", metadata, Column("foo", Integer))
- for meth in [table.exists, table.create, table.drop]:
+ for meth in [table.create, table.drop]:
assert_raises_message(
exc.UnboundExecutionError,
(
@@ -108,11 +111,11 @@ class BindTest(fixtures.TestBase):
)
assert metadata.bind is table.bind is bind
metadata.create_all()
- assert table.exists()
+ is_true(inspect(bind).has_table(table.name))
metadata.drop_all()
table.create()
table.drop()
- assert not table.exists()
+ is_false(inspect(bind).has_table(table.name))
finally:
if isinstance(bind, engine.Connection):
bind.close()
diff --git a/test/engine/test_deprecations.py b/test/engine/test_deprecations.py
index b9c09de16..502fe0245 100644
--- a/test/engine/test_deprecations.py
+++ b/test/engine/test_deprecations.py
@@ -6,7 +6,6 @@ from sqlalchemy import create_engine
from sqlalchemy import event
from sqlalchemy import ForeignKey
from sqlalchemy import func
-from sqlalchemy import inspect
from sqlalchemy import Integer
from sqlalchemy import literal
from sqlalchemy import MetaData
@@ -19,10 +18,13 @@ from sqlalchemy import TypeDecorator
from sqlalchemy.engine.base import Engine
from sqlalchemy.engine.mock import MockConnection
from sqlalchemy.interfaces import ConnectionProxy
+from sqlalchemy.testing import assert_raises
from sqlalchemy.testing import assert_raises_message
from sqlalchemy.testing import engines
from sqlalchemy.testing import eq_
from sqlalchemy.testing import fixtures
+from sqlalchemy.testing import is_false
+from sqlalchemy.testing import is_true
from sqlalchemy.testing.mock import Mock
from sqlalchemy.testing.schema import Column
from sqlalchemy.testing.schema import Table
@@ -62,38 +64,6 @@ class CreateEngineTest(fixtures.TestBase):
)
-class TableNamesOrderByTest(fixtures.TestBase):
- @testing.provide_metadata
- def test_order_by_foreign_key(self):
- Table(
- "t1",
- self.metadata,
- Column("id", Integer, primary_key=True),
- test_needs_acid=True,
- )
- Table(
- "t2",
- self.metadata,
- Column("id", Integer, primary_key=True),
- Column("t1id", Integer, ForeignKey("t1.id")),
- test_needs_acid=True,
- )
- Table(
- "t3",
- self.metadata,
- Column("id", Integer, primary_key=True),
- Column("t2id", Integer, ForeignKey("t2.id")),
- test_needs_acid=True,
- )
- self.metadata.create_all()
- insp = inspect(testing.db)
- with testing.expect_deprecated(
- "The get_table_names.order_by parameter is deprecated "
- ):
- tnames = insp.get_table_names(order_by="foreign_key")
- eq_(tnames, ["t1", "t2", "t3"])
-
-
def _proxy_execute_deprecated():
return (
testing.expect_deprecated("ConnectionProxy.execute is deprecated."),
@@ -103,6 +73,61 @@ def _proxy_execute_deprecated():
)
+class TransactionTest(fixtures.TestBase):
+ __backend__ = True
+
+ @classmethod
+ def setup_class(cls):
+ metadata = MetaData()
+ cls.users = Table(
+ "query_users",
+ metadata,
+ Column("user_id", Integer, primary_key=True),
+ Column("user_name", String(20)),
+ test_needs_acid=True,
+ )
+ cls.users.create(testing.db)
+
+ def teardown(self):
+ testing.db.execute(self.users.delete()).close()
+
+ @classmethod
+ def teardown_class(cls):
+ cls.users.drop(testing.db)
+
+ def test_transaction_container(self):
+ users = self.users
+
+ def go(conn, table, data):
+ for d in data:
+ conn.execute(table.insert(), d)
+
+ with testing.expect_deprecated(
+ r"The Engine.transaction\(\) method is deprecated"
+ ):
+ testing.db.transaction(
+ go, users, [dict(user_id=1, user_name="user1")]
+ )
+
+ with testing.db.connect() as conn:
+ eq_(conn.execute(users.select()).fetchall(), [(1, "user1")])
+ with testing.expect_deprecated(
+ r"The Engine.transaction\(\) method is deprecated"
+ ):
+ assert_raises(
+ tsa.exc.DBAPIError,
+ testing.db.transaction,
+ go,
+ users,
+ [
+ {"user_id": 2, "user_name": "user2"},
+ {"user_id": 1, "user_name": "user3"},
+ ],
+ )
+ with testing.db.connect() as conn:
+ eq_(conn.execute(users.select()).fetchall(), [(1, "user1")])
+
+
class ProxyConnectionTest(fixtures.TestBase):
"""These are the same tests as EngineEventsTest, except using
@@ -927,3 +952,162 @@ class ExplicitAutoCommitDeprecatedTest(fixtures.TestBase):
]
conn1.close()
conn2.close()
+
+
+class DeprecatedEngineFeatureTest(fixtures.TablesTest):
+ __backend__ = True
+
+ @classmethod
+ def define_tables(cls, metadata):
+ cls.table = Table(
+ "exec_test",
+ metadata,
+ Column("a", Integer),
+ Column("b", Integer),
+ test_needs_acid=True,
+ )
+
+ def _trans_fn(self, is_transaction=False):
+ def go(conn, x, value=None):
+ if is_transaction:
+ conn = conn.connection
+ conn.execute(self.table.insert().values(a=x, b=value))
+
+ return go
+
+ def _trans_rollback_fn(self, is_transaction=False):
+ def go(conn, x, value=None):
+ if is_transaction:
+ conn = conn.connection
+ conn.execute(self.table.insert().values(a=x, b=value))
+ raise SomeException("breakage")
+
+ return go
+
+ def _assert_no_data(self):
+ eq_(
+ testing.db.scalar(
+ select([func.count("*")]).select_from(self.table)
+ ),
+ 0,
+ )
+
+ def _assert_fn(self, x, value=None):
+ eq_(testing.db.execute(self.table.select()).fetchall(), [(x, value)])
+
+ def test_transaction_engine_fn_commit(self):
+ fn = self._trans_fn()
+ with testing.expect_deprecated(r"The Engine.transaction\(\) method"):
+ testing.db.transaction(fn, 5, value=8)
+ self._assert_fn(5, value=8)
+
+ def test_transaction_engine_fn_rollback(self):
+ fn = self._trans_rollback_fn()
+ with testing.expect_deprecated(
+ r"The Engine.transaction\(\) method is deprecated"
+ ):
+ assert_raises_message(
+ Exception, "breakage", testing.db.transaction, fn, 5, value=8
+ )
+ self._assert_no_data()
+
+ def test_transaction_connection_fn_commit(self):
+ fn = self._trans_fn()
+ with testing.db.connect() as conn:
+ with testing.expect_deprecated(
+ r"The Connection.transaction\(\) method is deprecated"
+ ):
+ conn.transaction(fn, 5, value=8)
+ self._assert_fn(5, value=8)
+
+ def test_transaction_connection_fn_rollback(self):
+ fn = self._trans_rollback_fn()
+ with testing.db.connect() as conn:
+ with testing.expect_deprecated(r""):
+ assert_raises(Exception, conn.transaction, fn, 5, value=8)
+ self._assert_no_data()
+
+
+class DeprecatedReflectionTest(fixtures.TablesTest):
+ @classmethod
+ def define_tables(cls, metadata):
+ Table(
+ "user",
+ metadata,
+ Column("id", Integer, primary_key=True),
+ Column("name", String(50)),
+ )
+ Table(
+ "address",
+ metadata,
+ Column("id", Integer, primary_key=True),
+ Column("user_id", ForeignKey("user.id")),
+ Column("email", String(50)),
+ )
+
+ def test_exists(self):
+ dont_exist = Table("dont_exist", MetaData())
+ with testing.expect_deprecated(
+ r"The Table.exists\(\) method is deprecated"
+ ):
+ is_false(dont_exist.exists(testing.db))
+
+ user = self.tables.user
+ with testing.expect_deprecated(
+ r"The Table.exists\(\) method is deprecated"
+ ):
+ is_true(user.exists(testing.db))
+
+ def test_create_drop_explicit(self):
+ metadata = MetaData()
+ table = Table("test_table", metadata, Column("foo", Integer))
+ for bind in (testing.db, testing.db.connect()):
+ for args in [([], {"bind": bind}), ([bind], {})]:
+ metadata.create_all(*args[0], **args[1])
+ with testing.expect_deprecated(
+ r"The Table.exists\(\) method is deprecated"
+ ):
+ assert table.exists(*args[0], **args[1])
+ metadata.drop_all(*args[0], **args[1])
+ table.create(*args[0], **args[1])
+ table.drop(*args[0], **args[1])
+ with testing.expect_deprecated(
+ r"The Table.exists\(\) method is deprecated"
+ ):
+ assert not table.exists(*args[0], **args[1])
+
+ def test_create_drop_err_table(self):
+ metadata = MetaData()
+ table = Table("test_table", metadata, Column("foo", Integer))
+
+ with testing.expect_deprecated(
+ r"The Table.exists\(\) method is deprecated"
+ ):
+ assert_raises_message(
+ tsa.exc.UnboundExecutionError,
+ (
+ "Table object 'test_table' is not bound to an Engine or "
+ "Connection."
+ ),
+ table.exists,
+ )
+
+ def test_engine_has_table(self):
+ with testing.expect_deprecated(
+ r"The Engine.has_table\(\) method is deprecated"
+ ):
+ is_false(testing.db.has_table("dont_exist"))
+
+ with testing.expect_deprecated(
+ r"The Engine.has_table\(\) method is deprecated"
+ ):
+ is_true(testing.db.has_table("user"))
+
+ def test_engine_table_names(self):
+ metadata = self.metadata
+
+ with testing.expect_deprecated(
+ r"The Engine.table_names\(\) method is deprecated"
+ ):
+ table_names = testing.db.table_names()
+ is_true(set(table_names).issuperset(metadata.tables))
diff --git a/test/engine/test_execute.py b/test/engine/test_execute.py
index 57c4b42f3..424631fe3 100644
--- a/test/engine/test_execute.py
+++ b/test/engine/test_execute.py
@@ -10,6 +10,7 @@ from sqlalchemy import create_engine
from sqlalchemy import create_mock_engine
from sqlalchemy import event
from sqlalchemy import func
+from sqlalchemy import inspect
from sqlalchemy import INT
from sqlalchemy import Integer
from sqlalchemy import LargeBinary
@@ -33,7 +34,9 @@ from sqlalchemy.testing import eq_
from sqlalchemy.testing import expect_warnings
from sqlalchemy.testing import fixtures
from sqlalchemy.testing import is_
+from sqlalchemy.testing import is_false
from sqlalchemy.testing import is_not_
+from sqlalchemy.testing import is_true
from sqlalchemy.testing import mock
from sqlalchemy.testing.assertsql import CompiledSQL
from sqlalchemy.testing.engines import testing_engine
@@ -839,30 +842,6 @@ class ConvenienceExecuteTest(fixtures.TablesTest):
# autocommit is off
self._assert_no_data()
- def test_transaction_engine_fn_commit(self):
- fn = self._trans_fn()
- testing.db.transaction(fn, 5, value=8)
- self._assert_fn(5, value=8)
-
- def test_transaction_engine_fn_rollback(self):
- fn = self._trans_rollback_fn()
- assert_raises_message(
- Exception, "breakage", testing.db.transaction, fn, 5, value=8
- )
- self._assert_no_data()
-
- def test_transaction_connection_fn_commit(self):
- fn = self._trans_fn()
- with testing.db.connect() as conn:
- conn.transaction(fn, 5, value=8)
- self._assert_fn(5, value=8)
-
- def test_transaction_connection_fn_rollback(self):
- fn = self._trans_rollback_fn()
- with testing.db.connect() as conn:
- assert_raises(Exception, conn.transaction, fn, 5, value=8)
- self._assert_no_data()
-
class CompiledCacheTest(fixtures.TestBase):
__backend__ = True
@@ -1126,18 +1105,20 @@ class SchemaTranslateTest(fixtures.TestBase, testing.AssertsExecutionResults):
) as conn:
metadata.create_all(conn)
- assert config.db.has_table("t1", schema=config.test_schema)
- assert config.db.has_table("t2", schema=config.test_schema)
- assert config.db.has_table("t3", schema=None)
+ insp = inspect(config.db)
+ is_true(insp.has_table("t1", schema=config.test_schema))
+ is_true(insp.has_table("t2", schema=config.test_schema))
+ is_true(insp.has_table("t3", schema=None))
with config.db.connect().execution_options(
schema_translate_map=map_
) as conn:
metadata.drop_all(conn)
- assert not config.db.has_table("t1", schema=config.test_schema)
- assert not config.db.has_table("t2", schema=config.test_schema)
- assert not config.db.has_table("t3", schema=None)
+ insp = inspect(config.db)
+ is_false(insp.has_table("t1", schema=config.test_schema))
+ is_false(insp.has_table("t2", schema=config.test_schema))
+ is_false(insp.has_table("t3", schema=None))
@testing.provide_metadata
def test_crud(self):
diff --git a/test/engine/test_reflection.py b/test/engine/test_reflection.py
index f6c19047e..2451822b1 100644
--- a/test/engine/test_reflection.py
+++ b/test/engine/test_reflection.py
@@ -24,6 +24,7 @@ from sqlalchemy.testing import eq_regex
from sqlalchemy.testing import expect_warnings
from sqlalchemy.testing import fixtures
from sqlalchemy.testing import in_
+from sqlalchemy.testing import is_false
from sqlalchemy.testing import is_true
from sqlalchemy.testing import mock
from sqlalchemy.testing import not_in_
@@ -1213,7 +1214,7 @@ class ReflectionTest(fixtures.TestBase, ComparesTables):
@testing.provide_metadata
def test_reflect_all(self):
- existing = testing.db.table_names()
+ existing = inspect(testing.db).get_table_names()
names = ["rt_%s" % name for name in ("a", "b", "c", "d", "e")]
nameset = set(names)
@@ -1298,15 +1299,16 @@ class ReflectionTest(fixtures.TestBase, ComparesTables):
m = MetaData()
- reflecttable = testing.db.dialect.reflecttable
+ inspector = sa.engine.reflection.Inspector
+ reflecttable = inspector.reflecttable
- def patched(conn, table, *arg, **kw):
+ def patched(self, table, *arg, **kw):
if table.name == "rt_c":
raise sa.exc.UnreflectableTableError("Can't reflect rt_c")
else:
- return reflecttable(conn, table, *arg, **kw)
+ return reflecttable(self, table, *arg, **kw)
- with mock.patch.object(testing.db.dialect, "reflecttable", patched):
+ with mock.patch.object(inspector, "reflecttable", patched):
with expect_warnings("Skipping table rt_c: Can't reflect rt_c"):
m.reflect(bind=testing.db)
@@ -1481,14 +1483,14 @@ class ReflectionTest(fixtures.TestBase, ComparesTables):
_drop_views(metadata.bind)
-class CreateDropTest(fixtures.TestBase):
+class CreateDropTest(fixtures.TablesTest):
__backend__ = True
+ run_create_tables = None
+
@classmethod
- def setup_class(cls):
- global metadata, users
- metadata = MetaData()
- users = Table(
+ def define_tables(cls, metadata):
+ Table(
"users",
metadata,
Column(
@@ -1509,7 +1511,7 @@ class CreateDropTest(fixtures.TestBase):
sa.Sequence("address_id_seq", optional=True),
primary_key=True,
),
- Column("user_id", sa.Integer, sa.ForeignKey(users.c.user_id)),
+ Column("user_id", sa.Integer, sa.ForeignKey("users.user_id")),
Column("email_address", sa.String(40)),
)
@@ -1522,7 +1524,7 @@ class CreateDropTest(fixtures.TestBase):
sa.Sequence("order_id_seq", optional=True),
primary_key=True,
),
- Column("user_id", sa.Integer, sa.ForeignKey(users.c.user_id)),
+ Column("user_id", sa.Integer, sa.ForeignKey("users.user_id")),
Column("description", sa.String(50)),
Column("isopen", sa.Integer),
)
@@ -1539,8 +1541,11 @@ class CreateDropTest(fixtures.TestBase):
Column("item_name", sa.VARCHAR(50)),
)
+ def teardown(self):
+ self.metadata.drop_all(testing.db)
+
def test_sorter(self):
- tables = metadata.sorted_tables
+ tables = self.metadata.sorted_tables
table_names = [t.name for t in tables]
ua = [n for n in table_names if n in ("users", "email_addresses")]
oi = [n for n in table_names if n in ("orders", "items")]
@@ -1549,42 +1554,41 @@ class CreateDropTest(fixtures.TestBase):
eq_(oi, ["orders", "items"])
def test_checkfirst(self):
- try:
- assert not users.exists(testing.db)
- users.create(bind=testing.db)
- assert users.exists(testing.db)
- users.create(bind=testing.db, checkfirst=True)
- users.drop(bind=testing.db)
- users.drop(bind=testing.db, checkfirst=True)
- assert not users.exists(bind=testing.db)
- users.create(bind=testing.db, checkfirst=True)
- users.drop(bind=testing.db)
- finally:
- metadata.drop_all(bind=testing.db)
+ insp = inspect(testing.db)
+ users = self.tables.users
+
+ is_false(insp.has_table("users"))
+ users.create(bind=testing.db)
+ is_true(insp.has_table("users"))
+ users.create(bind=testing.db, checkfirst=True)
+ users.drop(bind=testing.db)
+ users.drop(bind=testing.db, checkfirst=True)
+ is_false(insp.has_table("users"))
+ users.create(bind=testing.db, checkfirst=True)
+ users.drop(bind=testing.db)
def test_createdrop(self):
+ insp = inspect(testing.db)
+ metadata = self.metadata
metadata.create_all(bind=testing.db)
- eq_(testing.db.has_table("items"), True)
- eq_(testing.db.has_table("email_addresses"), True)
+ is_true(insp.has_table("items"))
+ is_true(insp.has_table("email_addresses"))
metadata.create_all(bind=testing.db)
- eq_(testing.db.has_table("items"), True)
+ is_true(insp.has_table("items"))
metadata.drop_all(bind=testing.db)
- eq_(testing.db.has_table("items"), False)
- eq_(testing.db.has_table("email_addresses"), False)
+ is_false(insp.has_table("items"))
+ is_false(insp.has_table("email_addresses"))
metadata.drop_all(bind=testing.db)
- eq_(testing.db.has_table("items"), False)
+ is_false(insp.has_table("items"))
def test_tablenames(self):
+ metadata = self.metadata
metadata.create_all(bind=testing.db)
+ insp = inspect(testing.db)
- # we only check to see if all the explicitly created tables are
- # there, rather than assertEqual -- the test db could have
- # "extra" tables if there is a misconfigured template. (*cough*
- # tsearch2 w/ the pg windows installer.)
-
- self.assert_(not set(metadata.tables) - set(testing.db.table_names()))
- metadata.drop_all(bind=testing.db)
+ # ensure all tables we created are in the list.
+ is_true(set(insp.get_table_names()).issuperset(metadata.tables))
class SchemaManipulationTest(fixtures.TestBase):
@@ -1692,8 +1696,9 @@ class UnicodeReflectionTest(fixtures.TestBase):
@testing.requires.unicode_connections
def test_has_table(self):
+ insp = inspect(testing.db)
for tname, cname, ixname in self.names:
- assert testing.db.has_table(tname), "Can't detect name %s" % tname
+ assert insp.has_table(tname), "Can't detect name %s" % tname
@testing.requires.unicode_connections
def test_basic(self):
@@ -1705,7 +1710,7 @@ class UnicodeReflectionTest(fixtures.TestBase):
bind = testing.db
names = set([rec[0] for rec in self.names])
- reflected = set(bind.table_names())
+ reflected = set(inspect(bind).get_table_names())
# Jython 2.5 on Java 5 lacks unicodedata.normalize
@@ -2103,7 +2108,7 @@ class CaseSensitiveTest(fixtures.TablesTest):
@testing.fails_if(testing.requires._has_mysql_on_windows)
def test_table_names(self):
- x = testing.db.run_callable(testing.db.dialect.get_table_names)
+ x = inspect(testing.db).get_table_names()
assert set(["SomeTable", "SomeOtherTable"]).issubset(x)
def test_reflect_exact_name(self):
diff --git a/test/engine/test_transaction.py b/test/engine/test_transaction.py
index 9d4dcda9f..595849bd5 100644
--- a/test/engine/test_transaction.py
+++ b/test/engine/test_transaction.py
@@ -12,7 +12,6 @@ from sqlalchemy import String
from sqlalchemy import testing
from sqlalchemy import text
from sqlalchemy import VARCHAR
-from sqlalchemy.testing import assert_raises
from sqlalchemy.testing import assert_raises_message
from sqlalchemy.testing import eq_
from sqlalchemy.testing import expect_warnings
@@ -97,25 +96,6 @@ class TransactionTest(fixtures.TestBase):
assert len(result.fetchall()) == 0
connection.close()
- def test_transaction_container(self):
- def go(conn, table, data):
- for d in data:
- conn.execute(table.insert(), d)
-
- testing.db.transaction(go, users, [dict(user_id=1, user_name="user1")])
- eq_(testing.db.execute(users.select()).fetchall(), [(1, "user1")])
- assert_raises(
- exc.DBAPIError,
- testing.db.transaction,
- go,
- users,
- [
- {"user_id": 2, "user_name": "user2"},
- {"user_id": 1, "user_name": "user3"},
- ],
- )
- eq_(testing.db.execute(users.select()).fetchall(), [(1, "user1")])
-
def test_nested_rollback(self):
connection = testing.db.connect()
try: