diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-08-02 12:34:16 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-08-06 18:05:45 -0400 |
| commit | 00b5c10846e800304caa86549ab9da373b42fa5d (patch) | |
| tree | 0832401deebeaad5fd6edc99158d0b10f958e716 /test/engine | |
| parent | e091775f1c4c817093e9a936a3abc79b5e311f93 (diff) | |
| download | sqlalchemy-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.py | 13 | ||||
| -rw-r--r-- | test/engine/test_deprecations.py | 250 | ||||
| -rw-r--r-- | test/engine/test_execute.py | 41 | ||||
| -rw-r--r-- | test/engine/test_reflection.py | 87 | ||||
| -rw-r--r-- | test/engine/test_transaction.py | 20 |
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: |
