summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/sqlalchemy/engine/reflection.py5
-rw-r--r--lib/sqlalchemy/testing/requirements.py8
-rw-r--r--lib/sqlalchemy/testing/suite/test_reflection.py56
3 files changed, 67 insertions, 2 deletions
diff --git a/lib/sqlalchemy/engine/reflection.py b/lib/sqlalchemy/engine/reflection.py
index 715781b7a..113aa8ea0 100644
--- a/lib/sqlalchemy/engine/reflection.py
+++ b/lib/sqlalchemy/engine/reflection.py
@@ -784,8 +784,9 @@ class Inspector(object):
cols_by_orig_name,
)
- if not found_table:
- raise exc.NoSuchTableError(table.name)
+ # NOTE: support tables/views with no columns
+ if not found_table and not self.has_table(table_name, schema):
+ raise exc.NoSuchTableError(table_name)
self._reflect_pk(
table_name, schema, table, cols_by_orig_name, exclude_columns
diff --git a/lib/sqlalchemy/testing/requirements.py b/lib/sqlalchemy/testing/requirements.py
index a546e1feb..f8b5dd606 100644
--- a/lib/sqlalchemy/testing/requirements.py
+++ b/lib/sqlalchemy/testing/requirements.py
@@ -589,9 +589,17 @@ class SuiteRequirements(Requirements):
@property
def table_reflection(self):
+ """target database has general support for table reflection"""
return exclusions.open()
@property
+ def reflect_tables_no_columns(self):
+ """target database supports creation and reflection of tables with no
+ columns, or at least tables that seem to have no columns."""
+
+ return exclusions.closed()
+
+ @property
def comment_reflection(self):
return exclusions.closed()
diff --git a/lib/sqlalchemy/testing/suite/test_reflection.py b/lib/sqlalchemy/testing/suite/test_reflection.py
index 916d74db3..88189c2d9 100644
--- a/lib/sqlalchemy/testing/suite/test_reflection.py
+++ b/lib/sqlalchemy/testing/suite/test_reflection.py
@@ -1063,6 +1063,61 @@ class ComponentReflectionTest(fixtures.TablesTest):
assert id_.get("autoincrement", True)
+class TableNoColumnsTest(fixtures.TestBase):
+ __requires__ = ("reflect_tables_no_columns",)
+ __backend__ = True
+
+ @testing.fixture
+ def table_no_columns(self, connection, metadata):
+ Table("empty", metadata)
+ metadata.create_all(connection)
+
+ @testing.fixture
+ def view_no_columns(self, connection, metadata):
+ Table("empty", metadata)
+ metadata.create_all(connection)
+
+ Table("empty", metadata)
+ event.listen(
+ metadata,
+ "after_create",
+ DDL("CREATE VIEW empty_v AS SELECT * FROM empty"),
+ )
+
+ # for transactional DDL the transaction is rolled back before this
+ # drop statement is invoked
+ event.listen(
+ metadata, "before_drop", DDL("DROP VIEW IF EXISTS empty_v")
+ )
+ metadata.create_all(connection)
+
+ @testing.requires.reflect_tables_no_columns
+ def test_reflect_table_no_columns(self, connection, table_no_columns):
+ t2 = Table("empty", MetaData(), autoload_with=connection)
+ eq_(list(t2.c), [])
+
+ @testing.requires.reflect_tables_no_columns
+ def test_get_columns_table_no_columns(self, connection, table_no_columns):
+ eq_(inspect(connection).get_columns("empty"), [])
+
+ @testing.requires.reflect_tables_no_columns
+ def test_reflect_incl_table_no_columns(self, connection, table_no_columns):
+ m = MetaData()
+ m.reflect(connection)
+ assert set(m.tables).intersection(["empty"])
+
+ @testing.requires.views
+ @testing.requires.reflect_tables_no_columns
+ def test_reflect_view_no_columns(self, connection, view_no_columns):
+ t2 = Table("empty_v", MetaData(), autoload_with=connection)
+ eq_(list(t2.c), [])
+
+ @testing.requires.views
+ @testing.requires.reflect_tables_no_columns
+ def test_get_columns_view_no_columns(self, connection, view_no_columns):
+ eq_(inspect(connection).get_columns("empty_v"), [])
+
+
class ComponentReflectionTestExtra(fixtures.TestBase):
__backend__ = True
@@ -1641,6 +1696,7 @@ class CompositeKeyReflectionTest(fixtures.TablesTest):
__all__ = (
"ComponentReflectionTest",
"ComponentReflectionTestExtra",
+ "TableNoColumnsTest",
"QuotedNameArgumentTest",
"HasTableTest",
"HasIndexTest",