]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
remove _implicit_subquery and all derived functions
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 16 Nov 2024 20:41:04 +0000 (15:41 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sun, 17 Nov 2024 13:19:53 +0000 (08:19 -0500)
The ``.c`` and ``.columns`` attributes on the :class:`.Select` and
:class:`.TextualSelect` constructs, which are not instances of
:class:`.FromClause`, have been removed completely, in addition to the
``.select()`` method as well as other codepaths which would implicitly
generate a subquery from a :class:`.Select` without the need to explicitly
call the :meth:`.Select.subquery` method.

In the case of ``.c`` and ``.columns``, these attributes were never useful
in practice and have caused a great deal of confusion, hence were
deprecated back in version 1.4, and have emitted warnings since that
version.   Accessing the columns that are specific to a :class:`.Select`
construct is done via the :attr:`.Select.selected_columns` attribute, which
was added in version 1.4 to suit the use case that users often expected
``.c`` to accomplish.  In the larger sense, implicit production of
subqueries works against SQLAlchemy's modern practice of making SQL
structure as explicit as possible.

Note that this is **not related** to the usual :attr:`.FromClause.c` and
:attr:`.FromClause.columns` attributes, common to objects such as
:class:`.Table` and :class:`.Subquery`,  which are unaffected by this
change.

Fixes: #10236
Change-Id: If241b8674ccacce7e860bfed25b5d266bfe1aca7

17 files changed:
doc/build/changelog/unreleased_21/10236.rst [new file with mode: 0644]
lib/sqlalchemy/orm/interfaces.py
lib/sqlalchemy/orm/mapper.py
lib/sqlalchemy/orm/query.py
lib/sqlalchemy/orm/util.py
lib/sqlalchemy/sql/coercions.py
lib/sqlalchemy/sql/roles.py
lib/sqlalchemy/sql/selectable.py
lib/sqlalchemy/testing/suite/__init__.py
lib/sqlalchemy/testing/suite/test_deprecations.py [deleted file]
test/aaa_profiling/test_memusage.py
test/orm/test_deprecations.py
test/sql/test_compiler.py
test/sql/test_deprecations.py
test/sql/test_operators.py
test/sql/test_roles.py
test/sql/test_selectable.py

diff --git a/doc/build/changelog/unreleased_21/10236.rst b/doc/build/changelog/unreleased_21/10236.rst
new file mode 100644 (file)
index 0000000..96e3b51
--- /dev/null
@@ -0,0 +1,30 @@
+.. change::
+    :tags: change, sql
+    :tickets: 10236
+
+    The ``.c`` and ``.columns`` attributes on the :class:`.Select` and
+    :class:`.TextualSelect` constructs, which are not instances of
+    :class:`.FromClause`, have been removed completely, in addition to the
+    ``.select()`` method as well as other codepaths which would implicitly
+    generate a subquery from a :class:`.Select` without the need to explicitly
+    call the :meth:`.Select.subquery` method.
+
+    In the case of ``.c`` and ``.columns``, these attributes were never useful
+    in practice and have caused a great deal of confusion, hence were
+    deprecated back in version 1.4, and have emitted warnings since that
+    version.   Accessing the columns that are specific to a :class:`.Select`
+    construct is done via the :attr:`.Select.selected_columns` attribute, which
+    was added in version 1.4 to suit the use case that users often expected
+    ``.c`` to accomplish.  In the larger sense, implicit production of
+    subqueries works against SQLAlchemy's modern practice of making SQL
+    structure as explicit as possible.
+
+    Note that this is **not related** to the usual :attr:`.FromClause.c` and
+    :attr:`.FromClause.columns` attributes, common to objects such as
+    :class:`.Table` and :class:`.Subquery`,  which are unaffected by this
+    change.
+
+    .. seealso::
+
+        :ref:`change_4617` - original notes from SQLAlchemy 1.4
+
index 1955abb97433cc7dc8d17eab1d07d7ef48351fa4..a9d7207d5d5c56a81848f1a833ef6a7ec3460c5d 100644 (file)
@@ -134,7 +134,7 @@ class ORMEntityColumnsClauseRole(ORMColumnsClauseRole[_T]):
     _role_name = "ORM mapped or aliased entity"
 
 
-class ORMFromClauseRole(roles.StrictFromClauseRole):
+class ORMFromClauseRole(roles.FromClauseRole):
     __slots__ = ()
     _role_name = "ORM mapped entity, aliased entity, or FROM expression"
 
index b15c6e051327972766bbc7e89fc46b23dff63e5b..53d2fa40eade1bc569bac605916d3b685cc927f4 100644 (file)
@@ -767,7 +767,7 @@ class Mapper(
 
         if local_table is not None:
             self.local_table = coercions.expect(
-                roles.StrictFromClauseRole,
+                roles.FromClauseRole,
                 local_table,
                 disable_inspection=True,
                 argname="local_table",
@@ -1416,9 +1416,8 @@ class Mapper(
             self.with_polymorphic = (
                 self.with_polymorphic[0],
                 coercions.expect(
-                    roles.StrictFromClauseRole,
+                    roles.FromClauseRole,
                     self.with_polymorphic[1],
-                    allow_select=True,
                 ),
             )
 
@@ -2918,7 +2917,8 @@ class Mapper(
     ) -> Tuple[Sequence[Mapper[Any]], FromClause]:
         if selectable not in (None, False):
             selectable = coercions.expect(
-                roles.StrictFromClauseRole, selectable, allow_select=True
+                roles.FromClauseRole,
+                selectable,
             )
 
         if self.with_polymorphic:
index 11936bbce8ca5fafce817e45dda651e5f67918af..fc1cf2b121111d85a484bd7f98e86c67c9b52eb6 100644 (file)
@@ -368,9 +368,8 @@ class Query(
     ) -> None:
         fa = [
             coercions.expect(
-                roles.StrictFromClauseRole,
+                roles.FromClauseRole,
                 elem,
-                allow_select=True,
                 apply_propagate_attrs=self,
             )
             for elem in obj
index 0360eb20e8a3c15984f039402b7327099f73ef54..eb74514d47f9706265a8ca96ed2d5dc6afeaa19b 100644 (file)
@@ -366,9 +366,7 @@ def polymorphic_union(
     for key in table_map:
         table = table_map[key]
 
-        table = coercions.expect(
-            roles.StrictFromClauseRole, table, allow_select=True
-        )
+        table = coercions.expect(roles.FromClauseRole, table)
         table_map[key] = table
 
         m = {}
index 136fc486463f6679d78e9e1b6c9abc9fcdc53782..63f9f8552923485f0728a217c4d0739fc2db9e71 100644 (file)
@@ -1273,25 +1273,12 @@ class FromClauseImpl(_SelectIsNotFrom, _NoTextCoercion, RoleImpl):
         argname: Optional[str] = None,
         *,
         explicit_subquery: bool = False,
-        allow_select: bool = True,
         **kw: Any,
     ) -> Any:
-        if resolved._is_select_base:
-            if explicit_subquery:
-                return resolved.subquery()
-            elif allow_select:
-                util.warn_deprecated(
-                    "Implicit coercion of SELECT and textual SELECT "
-                    "constructs into FROM clauses is deprecated; please call "
-                    ".subquery() on any Core select or ORM Query object in "
-                    "order to produce a subquery object.",
-                    version="1.4",
-                )
-                return resolved._implicit_subquery
-        elif resolved._is_text_clause:
-            return resolved
-        else:
-            self._raise_for_expected(element, argname, resolved)
+        if resolved._is_select_base and explicit_subquery:
+            return resolved.subquery()
+
+        self._raise_for_expected(element, argname, resolved)
 
     def _post_coercion(self, element, *, deannotate=False, **kw):
         if deannotate:
@@ -1300,32 +1287,7 @@ class FromClauseImpl(_SelectIsNotFrom, _NoTextCoercion, RoleImpl):
             return element
 
 
-class StrictFromClauseImpl(FromClauseImpl):
-    __slots__ = ()
-
-    def _implicit_coercions(
-        self,
-        element: Any,
-        resolved: Any,
-        argname: Optional[str] = None,
-        *,
-        allow_select: bool = False,
-        **kw: Any,
-    ) -> Any:
-        if resolved._is_select_base and allow_select:
-            util.warn_deprecated(
-                "Implicit coercion of SELECT and textual SELECT constructs "
-                "into FROM clauses is deprecated; please call .subquery() "
-                "on any Core select or ORM Query object in order to produce a "
-                "subquery object.",
-                version="1.4",
-            )
-            return resolved._implicit_subquery
-        else:
-            self._raise_for_expected(element, argname, resolved)
-
-
-class AnonymizedFromClauseImpl(StrictFromClauseImpl):
+class AnonymizedFromClauseImpl(FromClauseImpl):
     __slots__ = ()
 
     def _post_coercion(self, element, *, flat=False, name=None, **kw):
index ae70ac3a5bcae2cd892629d9b70c24d6128ed3d3..f37398cf61e20d2d151c4b2c51b68baa9ac632a6 100644 (file)
@@ -215,12 +215,7 @@ class FromClauseRole(ColumnsClauseRole, JoinTargetRole):
     named_with_column: bool
 
 
-class StrictFromClauseRole(FromClauseRole):
-    __slots__ = ()
-    # does not allow text() or select() objects
-
-
-class AnonymizedFromClauseRole(StrictFromClauseRole):
+class AnonymizedFromClauseRole(FromClauseRole):
     __slots__ = ()
 
     if TYPE_CHECKING:
index 3fd88739e5f5e76b8145a7bcab8591d88e996653..46ed0be33470e1ce68c543dca1866ba424428653 100644 (file)
@@ -842,7 +842,7 @@ class FromClause(roles.AnonymizedFromClauseRole, Selectable):
     ) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]:
         """A :class:`_expression.ColumnCollection`
         that represents the "exported"
-        columns of this :class:`_expression.Selectable`.
+        columns of this :class:`_expression.FromClause`.
 
         The "exported" columns for a :class:`_expression.FromClause`
         object are synonymous
@@ -1751,9 +1751,9 @@ class Alias(roles.DMLTableRole, FromClauseAlias):
         name: Optional[str] = None,
         flat: bool = False,
     ) -> NamedFromClause:
-        return coercions.expect(
-            roles.FromClauseRole, selectable, allow_select=True
-        ).alias(name=name, flat=flat)
+        return coercions.expect(roles.FromClauseRole, selectable).alias(
+            name=name, flat=flat
+        )
 
 
 class TableValuedAlias(LateralFromClause, Alias):
@@ -3485,29 +3485,6 @@ class SelectBase(
         """
         return self.selected_columns.as_readonly()
 
-    @property
-    @util.deprecated(
-        "1.4",
-        "The :attr:`_expression.SelectBase.c` and "
-        ":attr:`_expression.SelectBase.columns` attributes "
-        "are deprecated and will be removed in a future release; these "
-        "attributes implicitly create a subquery that should be explicit.  "
-        "Please call :meth:`_expression.SelectBase.subquery` "
-        "first in order to create "
-        "a subquery, which then contains this attribute.  To access the "
-        "columns that this SELECT object SELECTs "
-        "from, use the :attr:`_expression.SelectBase.selected_columns` "
-        "attribute.",
-    )
-    def c(self) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]:
-        return self._implicit_subquery.columns
-
-    @property
-    def columns(
-        self,
-    ) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]:
-        return self.c
-
     def get_label_style(self) -> SelectLabelStyle:
         """
         Retrieve the current label style.
@@ -3526,22 +3503,6 @@ class SelectBase(
 
         raise NotImplementedError()
 
-    @util.deprecated(
-        "1.4",
-        "The :meth:`_expression.SelectBase.select` method is deprecated "
-        "and will be removed in a future release; this method implicitly "
-        "creates a subquery that should be explicit.  "
-        "Please call :meth:`_expression.SelectBase.subquery` "
-        "first in order to create "
-        "a subquery, which then can be selected.",
-    )
-    def select(self, *arg: Any, **kw: Any) -> Select[Unpack[TupleAny]]:
-        return self._implicit_subquery.select(*arg, **kw)
-
-    @HasMemoized.memoized_attribute
-    def _implicit_subquery(self) -> Subquery:
-        return self.subquery()
-
     def _scalar_type(self) -> TypeEngine[Any]:
         raise NotImplementedError()
 
index a146cb3163c2a934b68cf8a95c91fc59c9322a20..ee4b33b0a23afe51c6ce557f6cc98384bc8cb1cc 100644 (file)
@@ -6,7 +6,6 @@
 # the MIT License: https://www.opensource.org/licenses/mit-license.php
 from .test_cte import *  # noqa
 from .test_ddl import *  # noqa
-from .test_deprecations import *  # noqa
 from .test_dialect import *  # noqa
 from .test_insert import *  # noqa
 from .test_reflection import *  # noqa
diff --git a/lib/sqlalchemy/testing/suite/test_deprecations.py b/lib/sqlalchemy/testing/suite/test_deprecations.py
deleted file mode 100644 (file)
index dc6a71a..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-# testing/suite/test_deprecations.py
-# Copyright (C) 2005-2024 the SQLAlchemy authors and contributors
-# <see AUTHORS file>
-#
-# This module is part of SQLAlchemy and is released under
-# the MIT License: https://www.opensource.org/licenses/mit-license.php
-# mypy: ignore-errors
-
-from .. import fixtures
-from ..assertions import eq_
-from ..schema import Column
-from ..schema import Table
-from ... import Integer
-from ... import select
-from ... import testing
-from ... import union
-
-
-class DeprecatedCompoundSelectTest(fixtures.TablesTest):
-    __backend__ = True
-
-    @classmethod
-    def define_tables(cls, metadata):
-        Table(
-            "some_table",
-            metadata,
-            Column("id", Integer, primary_key=True),
-            Column("x", Integer),
-            Column("y", Integer),
-        )
-
-    @classmethod
-    def insert_data(cls, connection):
-        connection.execute(
-            cls.tables.some_table.insert(),
-            [
-                {"id": 1, "x": 1, "y": 2},
-                {"id": 2, "x": 2, "y": 3},
-                {"id": 3, "x": 3, "y": 4},
-                {"id": 4, "x": 4, "y": 5},
-            ],
-        )
-
-    def _assert_result(self, conn, select, result, params=None):
-        eq_(conn.execute(select, params).fetchall(), result)
-
-    def test_plain_union(self, connection):
-        table = self.tables.some_table
-        s1 = select(table).where(table.c.id == 2)
-        s2 = select(table).where(table.c.id == 3)
-
-        u1 = union(s1, s2)
-        with testing.expect_deprecated(
-            "The SelectBase.c and SelectBase.columns "
-            "attributes are deprecated"
-        ):
-            self._assert_result(
-                connection, u1.order_by(u1.c.id), [(2, 2, 3), (3, 3, 4)]
-            )
-
-    # note we've had to remove one use case entirely, which is this
-    # one.   the Select gets its FROMS from the WHERE clause and the
-    # columns clause, but not the ORDER BY, which means the old ".c" system
-    # allowed you to "order_by(s.c.foo)" to get an unnamed column in the
-    # ORDER BY without adding the SELECT into the FROM and breaking the
-    # query.  Users will have to adjust for this use case if they were doing
-    # it before.
-    def _dont_test_select_from_plain_union(self, connection):
-        table = self.tables.some_table
-        s1 = select(table).where(table.c.id == 2)
-        s2 = select(table).where(table.c.id == 3)
-
-        u1 = union(s1, s2).alias().select()
-        with testing.expect_deprecated(
-            "The SelectBase.c and SelectBase.columns "
-            "attributes are deprecated"
-        ):
-            self._assert_result(
-                connection, u1.order_by(u1.c.id), [(2, 2, 3), (3, 3, 4)]
-            )
-
-    @testing.requires.order_by_col_from_union
-    @testing.requires.parens_in_union_contained_select_w_limit_offset
-    def test_limit_offset_selectable_in_unions(self, connection):
-        table = self.tables.some_table
-        s1 = select(table).where(table.c.id == 2).limit(1).order_by(table.c.id)
-        s2 = select(table).where(table.c.id == 3).limit(1).order_by(table.c.id)
-
-        u1 = union(s1, s2).limit(2)
-        with testing.expect_deprecated(
-            "The SelectBase.c and SelectBase.columns "
-            "attributes are deprecated"
-        ):
-            self._assert_result(
-                connection, u1.order_by(u1.c.id), [(2, 2, 3), (3, 3, 4)]
-            )
-
-    @testing.requires.parens_in_union_contained_select_wo_limit_offset
-    def test_order_by_selectable_in_unions(self, connection):
-        table = self.tables.some_table
-        s1 = select(table).where(table.c.id == 2).order_by(table.c.id)
-        s2 = select(table).where(table.c.id == 3).order_by(table.c.id)
-
-        u1 = union(s1, s2).limit(2)
-        with testing.expect_deprecated(
-            "The SelectBase.c and SelectBase.columns "
-            "attributes are deprecated"
-        ):
-            self._assert_result(
-                connection, u1.order_by(u1.c.id), [(2, 2, 3), (3, 3, 4)]
-            )
-
-    def test_distinct_selectable_in_unions(self, connection):
-        table = self.tables.some_table
-        s1 = select(table).where(table.c.id == 2).distinct()
-        s2 = select(table).where(table.c.id == 3).distinct()
-
-        u1 = union(s1, s2).limit(2)
-        with testing.expect_deprecated(
-            "The SelectBase.c and SelectBase.columns "
-            "attributes are deprecated"
-        ):
-            self._assert_result(
-                connection, u1.order_by(u1.c.id), [(2, 2, 3), (3, 3, 4)]
-            )
-
-    def test_limit_offset_aliased_selectable_in_unions(self, connection):
-        table = self.tables.some_table
-        s1 = (
-            select(table)
-            .where(table.c.id == 2)
-            .limit(1)
-            .order_by(table.c.id)
-            .alias()
-            .select()
-        )
-        s2 = (
-            select(table)
-            .where(table.c.id == 3)
-            .limit(1)
-            .order_by(table.c.id)
-            .alias()
-            .select()
-        )
-
-        u1 = union(s1, s2).limit(2)
-        with testing.expect_deprecated(
-            "The SelectBase.c and SelectBase.columns "
-            "attributes are deprecated"
-        ):
-            self._assert_result(
-                connection, u1.order_by(u1.c.id), [(2, 2, 3), (3, 3, 4)]
-            )
index 94629b14163e552f89ae2355b4e7ccc746fdeaba..230832a714411247b5e9fedc103fa84e1082f1d0 100644 (file)
@@ -1084,62 +1084,6 @@ class MemUsageWBackendTest(fixtures.MappedTest, EnsureZeroed):
     # in pysqlite itself. background at:
     # https://thread.gmane.org/gmane.comp.python.db.pysqlite.user/2290
 
-    @testing.crashes("mysql+cymysql", "blocking")
-    def test_join_cache_deprecated_coercion(self):
-        metadata = MetaData()
-        table1 = Table(
-            "table1",
-            metadata,
-            Column(
-                "id", Integer, primary_key=True, test_needs_autoincrement=True
-            ),
-            Column("data", String(30)),
-        )
-        table2 = Table(
-            "table2",
-            metadata,
-            Column(
-                "id", Integer, primary_key=True, test_needs_autoincrement=True
-            ),
-            Column("data", String(30)),
-            Column("t1id", Integer, ForeignKey("table1.id")),
-        )
-
-        class Foo:
-            pass
-
-        class Bar:
-            pass
-
-        self.mapper_registry.map_imperatively(
-            Foo,
-            table1,
-            properties={
-                "bars": relationship(
-                    self.mapper_registry.map_imperatively(Bar, table2)
-                )
-            },
-        )
-        metadata.create_all(self.engine)
-        session = sessionmaker(self.engine)
-
-        @profile_memory()
-        def go():
-            s = table2.select()
-            sess = session()
-            with testing.expect_deprecated(
-                "Implicit coercion of SELECT and textual SELECT constructs",
-                "An alias is being generated automatically",
-                assert_=False,
-            ):
-                sess.query(Foo).join(s, Foo.bars).all()
-            sess.rollback()
-
-        try:
-            go()
-        finally:
-            metadata.drop_all(self.engine)
-
     @testing.crashes("mysql+cymysql", "blocking")
     def test_join_cache(self):
         metadata = MetaData()
index 9721c96dca58dd68477230d5086f429c736de3d6..81d0d926f5c5466234126bff157e18e18a522544 100644 (file)
@@ -46,7 +46,6 @@ from sqlalchemy.orm import undefer
 from sqlalchemy.orm import with_parent
 from sqlalchemy.orm import with_polymorphic
 from sqlalchemy.orm.collections import collection
-from sqlalchemy.orm.util import polymorphic_union
 from sqlalchemy.testing import assert_raises_message
 from sqlalchemy.testing import assertions
 from sqlalchemy.testing import AssertsCompiledSQL
@@ -56,7 +55,6 @@ from sqlalchemy.testing import expect_deprecated
 from sqlalchemy.testing import expect_raises_message
 from sqlalchemy.testing import fixtures
 from sqlalchemy.testing import is_
-from sqlalchemy.testing import is_true
 from sqlalchemy.testing import mock
 from sqlalchemy.testing.entities import ComparableEntity
 from sqlalchemy.testing.fixtures import CacheKeyFixture
@@ -494,34 +492,6 @@ class DeprecatedQueryTest(_fixtures.FixtureTest, AssertsCompiledSQL):
     def setup_mappers(cls):
         cls._setup_stock_mapping()
 
-    @classmethod
-    def _expect_implicit_subquery(cls):
-        return assertions.expect_deprecated(
-            "Implicit coercion of SELECT and textual SELECT constructs into "
-            r"FROM clauses is deprecated; please call \.subquery\(\) on any "
-            "Core select or ORM Query object in order to produce a "
-            "subquery object."
-        )
-
-    def test_deprecated_select_coercion_join_target(self):
-        User = self.classes.User
-        addresses = self.tables.addresses
-
-        s = addresses.select()
-        sess = fixture_session()
-        with testing.expect_deprecated(
-            "Implicit coercion of SELECT and textual SELECT constructs",
-            "An alias is being generated automatically against joined entity",
-        ):
-            self.assert_compile(
-                sess.query(User).join(s, User.addresses),
-                "SELECT users.id AS users_id, users.name AS users_name "
-                "FROM users JOIN (SELECT addresses.id AS id, "
-                "addresses.user_id AS user_id, addresses.email_address "
-                "AS email_address FROM addresses) AS anon_1 "
-                "ON users.id = anon_1.user_id",
-            )
-
     def test_invalid_column(self):
         User = self.classes.User
 
@@ -570,20 +540,6 @@ class DeprecatedQueryTest(_fixtures.FixtureTest, AssertsCompiledSQL):
         ):
             s.query(User).as_scalar()
 
-    def test_select_from_q_statement_no_aliasing(self):
-        User = self.classes.User
-        sess = fixture_session()
-
-        q = sess.query(User)
-        with self._expect_implicit_subquery():
-            q = sess.query(User).select_from(User, q.statement)
-        self.assert_compile(
-            q.filter(User.name == "ed"),
-            "SELECT users.id AS users_id, users.name AS users_name "
-            "FROM users, (SELECT users.id AS id, users.name AS name FROM "
-            "users) AS anon_1 WHERE users.name = :name_1",
-        )
-
     def test_apply_labels(self):
         User = self.classes.User
 
@@ -653,19 +609,6 @@ class LazyLoadOptSpecificityTest(fixtures.DeclarativeMappedTest):
         self.assert_sql_count(testing.db, go, expected)
 
 
-class DeprecatedInhTest(_poly_fixtures._Polymorphic):
-    def test_with_polymorphic(self):
-        Person = _poly_fixtures.Person
-        Engineer = _poly_fixtures.Engineer
-
-        with DeprecatedQueryTest._expect_implicit_subquery():
-            p_poly = with_polymorphic(Person, [Engineer], select(Person))
-
-        is_true(
-            sa.inspect(p_poly).selectable.compare(select(Person).subquery())
-        )
-
-
 class DeprecatedMapperTest(
     fixtures.RemovesEvents, _fixtures.FixtureTest, AssertsCompiledSQL
 ):
@@ -763,26 +706,6 @@ class DeprecatedMapperTest(
         ):
             is_(manager.deferred_scalar_loader, myloader)
 
-    def test_polymorphic_union_w_select(self):
-        users, addresses = self.tables.users, self.tables.addresses
-
-        with DeprecatedQueryTest._expect_implicit_subquery():
-            dep = polymorphic_union(
-                {"u": users.select(), "a": addresses.select()},
-                "type",
-                "bcjoin",
-            )
-
-        subq_version = polymorphic_union(
-            {
-                "u": users.select().subquery(),
-                "a": addresses.select().subquery(),
-            },
-            "type",
-            "bcjoin",
-        )
-        is_true(dep.compare(subq_version))
-
     def test_comparable_column(self):
         users, User = self.tables.users, self.classes.User
 
index 3e8fca59a887a9bd56cadd94edb38faa058f584d..9e5d11bbfdff8f3b796ed3720f548ac02990eec7 100644 (file)
@@ -264,11 +264,6 @@ class SelectTest(fixtures.TestBase, AssertsCompiledSQL):
         assert not hasattr(table1.select().subquery().c.myid, "columns")
         assert not hasattr(table1.alias().c.myid, "columns")
         assert not hasattr(table1.alias().c.myid, "c")
-        with testing.expect_deprecated(
-            "The SelectBase.c and SelectBase.columns attributes are "
-            "deprecated"
-        ):
-            assert hasattr(table1.select(), "c")
 
         assert_raises_message(
             exc.InvalidRequestError,
index 96b636bd058fc12be97d29f9557d71257bf142a6..4cd5c6402a1b97ba8c4cbb3cc70166831dc62d92 100644 (file)
@@ -1,33 +1,21 @@
-from sqlalchemy import alias
 from sqlalchemy import and_
-from sqlalchemy import bindparam
 from sqlalchemy import CHAR
 from sqlalchemy import column
 from sqlalchemy import exc
 from sqlalchemy import ForeignKey
 from sqlalchemy import func
 from sqlalchemy import Integer
-from sqlalchemy import join
 from sqlalchemy import literal_column
 from sqlalchemy import MetaData
-from sqlalchemy import null
 from sqlalchemy import or_
 from sqlalchemy import schema
 from sqlalchemy import select
 from sqlalchemy import Sequence
-from sqlalchemy import sql
 from sqlalchemy import String
 from sqlalchemy import table
 from sqlalchemy import testing
-from sqlalchemy import text
 from sqlalchemy.engine import default
-from sqlalchemy.sql import coercions
-from sqlalchemy.sql import LABEL_STYLE_TABLENAME_PLUS_COL
 from sqlalchemy.sql import operators
-from sqlalchemy.sql import quoted_name
-from sqlalchemy.sql import roles
-from sqlalchemy.sql import visitors
-from sqlalchemy.sql.selectable import SelectStatementGrouping
 from sqlalchemy.testing import assertions
 from sqlalchemy.testing import AssertsCompiledSQL
 from sqlalchemy.testing import config
@@ -127,31 +115,6 @@ class SubqueryCoercionsTest(fixtures.TestBase, AssertsCompiledSQL):
         "myothertable", column("otherid", Integer), column("othername", String)
     )
 
-    def test_select_of_select(self):
-        stmt = select(self.table1.c.myid)
-
-        with testing.expect_deprecated(
-            r"The SelectBase.select\(\) method is deprecated and will be "
-            "removed"
-        ):
-            self.assert_compile(
-                stmt.select(),
-                "SELECT anon_1.myid FROM (SELECT mytable.myid AS myid "
-                "FROM mytable) AS anon_1",
-            )
-
-    def test_standalone_alias(self):
-        with testing.expect_deprecated(
-            "Implicit coercion of SELECT and textual SELECT constructs"
-        ):
-            stmt = alias(select(self.table1.c.myid), "foo")
-
-        self.assert_compile(stmt, "SELECT mytable.myid FROM mytable")
-
-        is_true(
-            stmt.compare(select(self.table1.c.myid).subquery().alias("foo"))
-        )
-
     def test_as_scalar(self):
         with testing.expect_deprecated(
             r"The SelectBase.as_scalar\(\) method is deprecated and "
@@ -170,64 +133,6 @@ class SubqueryCoercionsTest(fixtures.TestBase, AssertsCompiledSQL):
 
         is_true(stmt.compare(select(self.table1.c.myid).scalar_subquery()))
 
-    def test_fromclause_subquery(self):
-        stmt = select(self.table1.c.myid)
-        with testing.expect_deprecated(
-            "Implicit coercion of SELECT and textual SELECT constructs "
-            "into FROM clauses is deprecated"
-        ):
-            coerced = coercions.expect(
-                roles.StrictFromClauseRole, stmt, allow_select=True
-            )
-
-        is_true(coerced.compare(stmt.subquery()))
-
-    def test_plain_fromclause_select_to_subquery(self):
-        with testing.expect_deprecated(
-            "Implicit coercion of SELECT and textual SELECT "
-            "constructs into FROM clauses is deprecated;"
-        ):
-            element = coercions.expect(
-                roles.FromClauseRole,
-                SelectStatementGrouping(select(self.table1)),
-            )
-            is_true(
-                element.compare(
-                    SelectStatementGrouping(select(self.table1)).subquery()
-                )
-            )
-
-    def test_functions_select_method_two(self):
-        expr = func.rows("foo")
-        with testing.expect_deprecated(
-            "Implicit coercion of SELECT and textual SELECT constructs "
-            "into FROM clauses is deprecated"
-        ):
-            stmt = select("*").select_from(expr.select())
-        self.assert_compile(
-            stmt, "SELECT * FROM (SELECT rows(:rows_2) AS rows_1) AS anon_1"
-        )
-
-    def test_functions_with_cols(self):
-        users = table(
-            "users", column("id"), column("name"), column("fullname")
-        )
-        calculate = select(column("q"), column("z"), column("r")).select_from(
-            func.calculate(bindparam("x", None), bindparam("y", None))
-        )
-
-        with testing.expect_deprecated(
-            "The SelectBase.c and SelectBase.columns attributes are "
-            "deprecated and will be removed"
-        ):
-            self.assert_compile(
-                select(users).where(users.c.id > calculate.c.z),
-                "SELECT users.id, users.name, users.fullname "
-                "FROM users, (SELECT q, z, r "
-                "FROM calculate(:x, :y)) AS anon_1 "
-                "WHERE users.id > anon_1.z",
-            )
-
 
 class LateralSubqueryCoercionsTest(fixtures.TablesTest, AssertsCompiledSQL):
     __dialect__ = default.DefaultDialect(supports_native_boolean=True)
@@ -338,214 +243,6 @@ class SelectableTest(fixtures.TestBase, AssertsCompiledSQL):
             "ON basefrom.a = joinfrom.a",
         )
 
-    def test_against_cloned_non_table(self):
-        # test that corresponding column digs across
-        # clone boundaries with anonymous labeled elements
-        col = func.count().label("foo")
-        sel = select(col)
-
-        sel2 = visitors.ReplacingCloningVisitor().traverse(sel)
-        with testing.expect_deprecated("The SelectBase.c"):
-            assert (
-                sel2._implicit_subquery.corresponding_column(col) is sel2.c.foo
-            )
-
-        sel3 = visitors.ReplacingCloningVisitor().traverse(sel2)
-        with testing.expect_deprecated("The SelectBase.c"):
-            assert (
-                sel3._implicit_subquery.corresponding_column(col) is sel3.c.foo
-            )
-
-    def test_alias_union(self):
-        # same as testunion, except its an alias of the union
-
-        u = (
-            select(
-                self.table1.c.col1,
-                self.table1.c.col2,
-                self.table1.c.col3,
-                self.table1.c.colx,
-                null().label("coly"),
-            )
-            .union(
-                select(
-                    self.table2.c.col1,
-                    self.table2.c.col2,
-                    self.table2.c.col3,
-                    null().label("colx"),
-                    self.table2.c.coly,
-                )
-            )
-            .alias("analias")
-        )
-        s1 = self.table1.select().set_label_style(
-            LABEL_STYLE_TABLENAME_PLUS_COL
-        )
-        s2 = self.table2.select().set_label_style(
-            LABEL_STYLE_TABLENAME_PLUS_COL
-        )
-        with self._c_deprecated():
-            assert u.corresponding_column(s1.c.table1_col2) is u.c.col2
-            assert u.corresponding_column(s2.c.table2_col2) is u.c.col2
-            assert u.corresponding_column(s2.c.table2_coly) is u.c.coly
-            assert s2.c.corresponding_column(u.c.coly) is s2.c.table2_coly
-
-    def test_join_against_self_implicit_subquery(self):
-        jj = select(self.table1.c.col1.label("bar_col1"))
-        with testing.expect_deprecated(
-            "The SelectBase.c and SelectBase.columns attributes are "
-            "deprecated and will be removed",
-            "Implicit coercion of SELECT",
-        ):
-            jjj = join(self.table1, jj, self.table1.c.col1 == jj.c.bar_col1)
-
-        jjj_bar_col1 = jjj.c["%s_bar_col1" % jj._implicit_subquery.name]
-        assert jjj_bar_col1 is not None
-
-        # test column directly against itself
-
-        assert jjj.corresponding_column(jjj.c.table1_col1) is jjj.c.table1_col1
-        with testing.expect_deprecated(
-            "The SelectBase.c and SelectBase.columns attributes are "
-            "deprecated and will be removed"
-        ):
-            assert jjj.corresponding_column(jj.c.bar_col1) is jjj_bar_col1
-
-    def test_select_labels(self):
-        a = self.table1.select().set_label_style(
-            LABEL_STYLE_TABLENAME_PLUS_COL
-        )
-        j = join(a._implicit_subquery, self.table2)
-
-        criterion = a._implicit_subquery.c.table1_col1 == self.table2.c.col2
-        self.assert_(criterion.compare(j.onclause))
-
-
-class QuoteTest(fixtures.TestBase, AssertsCompiledSQL):
-    __dialect__ = "default"
-
-    def test_literal_column_label_embedded_select_samename_explicit_quote(
-        self,
-    ):
-        col = sql.literal_column("NEEDS QUOTES").label(
-            quoted_name("NEEDS QUOTES", True)
-        )
-
-        with testing.expect_deprecated(
-            r"The SelectBase.select\(\) method is deprecated"
-        ):
-            self.assert_compile(
-                select(col).select(),
-                'SELECT anon_1."NEEDS QUOTES" FROM '
-                '(SELECT NEEDS QUOTES AS "NEEDS QUOTES") AS anon_1',
-            )
-
-    def test_literal_column_label_embedded_select_diffname_explicit_quote(
-        self,
-    ):
-        col = sql.literal_column("NEEDS QUOTES").label(
-            quoted_name("NEEDS QUOTES_", True)
-        )
-
-        with testing.expect_deprecated(
-            r"The SelectBase.select\(\) method is deprecated"
-        ):
-            self.assert_compile(
-                select(col).select(),
-                'SELECT anon_1."NEEDS QUOTES_" FROM '
-                '(SELECT NEEDS QUOTES AS "NEEDS QUOTES_") AS anon_1',
-            )
-
-    def test_literal_column_label_embedded_select_diffname(self):
-        col = sql.literal_column("NEEDS QUOTES").label("NEEDS QUOTES_")
-
-        with testing.expect_deprecated(
-            r"The SelectBase.select\(\) method is deprecated"
-        ):
-            self.assert_compile(
-                select(col).select(),
-                'SELECT anon_1."NEEDS QUOTES_" FROM (SELECT NEEDS QUOTES AS '
-                '"NEEDS QUOTES_") AS anon_1',
-            )
-
-    def test_literal_column_label_embedded_select_samename(self):
-        col = sql.literal_column("NEEDS QUOTES").label("NEEDS QUOTES")
-
-        with testing.expect_deprecated(
-            r"The SelectBase.select\(\) method is deprecated"
-        ):
-            self.assert_compile(
-                select(col).select(),
-                'SELECT anon_1."NEEDS QUOTES" FROM (SELECT NEEDS QUOTES AS '
-                '"NEEDS QUOTES") AS anon_1',
-            )
-
-
-class TextualSelectTest(fixtures.TestBase, AssertsCompiledSQL):
-    __dialect__ = "default"
-
-    table1 = table(
-        "mytable",
-        column("myid", Integer),
-        column("name", String),
-        column("description", String),
-    )
-
-    table2 = table(
-        "myothertable", column("otherid", Integer), column("othername", String)
-    )
-
-    def test_basic_subquery_resultmap(self):
-        table1 = self.table1
-        t = text("select id, name from user").columns(id=Integer, name=String)
-
-        with testing.expect_deprecated(
-            "The SelectBase.c and SelectBase.columns", "Implicit coercion"
-        ):
-            stmt = select(table1.c.myid).select_from(
-                table1.join(t, table1.c.myid == t.c.id)
-            )
-        compiled = stmt.compile()
-        eq_(
-            compiled._create_result_map(),
-            {
-                "myid": (
-                    "myid",
-                    (table1.c.myid, "myid", "myid", "mytable_myid"),
-                    table1.c.myid.type,
-                    0,
-                )
-            },
-        )
-
-    def test_column_collection_ordered(self):
-        t = text("select a, b, c from foo").columns(
-            column("a"), column("b"), column("c")
-        )
-        with testing.expect_deprecated(
-            "The SelectBase.c and SelectBase.columns"
-        ):
-            eq_(t.c.keys(), ["a", "b", "c"])
-
-    def test_column_collection_pos_plus_bykey(self):
-        # overlapping positional names + type names
-        t = text("select a, b, c from foo").columns(
-            column("a"), column("b"), b=Integer, c=String
-        )
-
-        with testing.expect_deprecated(
-            "The SelectBase.c and SelectBase.columns"
-        ):
-            eq_(t.c.keys(), ["a", "b", "c"])
-        with testing.expect_deprecated(
-            "The SelectBase.c and SelectBase.columns"
-        ):
-            eq_(t.c.b.type._type_affinity, Integer)
-        with testing.expect_deprecated(
-            "The SelectBase.c and SelectBase.columns"
-        ):
-            eq_(t.c.c.type._type_affinity, String)
-
 
 class KeyTargetingTest(fixtures.TablesTest):
     run_inserts = "once"
index 8afe091925ae7f21a4b4ba708eea4287a29fdd82..1804d02ca9b6e025bbc48c5dfa36db075136e59b 100644 (file)
@@ -739,16 +739,6 @@ class _CustomComparatorTests:
         c1 = Column("foo", self._add_override_factory())
         self._assert_add_override(c1)
 
-    def test_column_proxy(self):
-        t = Table("t", MetaData(), Column("foo", self._add_override_factory()))
-        with testing.expect_deprecated(
-            "The SelectBase.c and SelectBase.columns attributes "
-            "are deprecated"
-        ):
-            proxied = t.select().c.foo
-        self._assert_add_override(proxied)
-        self._assert_and_override(proxied)
-
     def test_subquery_proxy(self):
         t = Table("t", MetaData(), Column("foo", self._add_override_factory()))
         proxied = t.select().subquery().c.foo
index 09e34691e8c2c45a67a541c55bc0587f4c9b6760..1c97dd181df27a3c37de9dc626978d12e34b5ee7 100644 (file)
@@ -32,6 +32,7 @@ from sqlalchemy.sql.selectable import SelectStatementGrouping
 from sqlalchemy.testing import assert_raises
 from sqlalchemy.testing import assert_raises_message
 from sqlalchemy.testing import AssertsCompiledSQL
+from sqlalchemy.testing import expect_raises_message
 from sqlalchemy.testing import fixtures
 from sqlalchemy.testing import is_
 from sqlalchemy.testing import is_instance_of
@@ -262,16 +263,11 @@ class RoleTest(fixtures.TestBase):
         )
 
     def test_select_is_coerced_into_fromclause_w_deprecation(self):
-        with testing.expect_deprecated(
-            "Implicit coercion of SELECT and textual SELECT "
-            "constructs into FROM clauses is deprecated;"
+        with testing.expect_raises_message(
+            exc.ArgumentError,
+            r"FROM expression, such as a Table or alias\(\) object expected",
         ):
-            element = expect(
-                roles.FromClauseRole, SelectStatementGrouping(select(t))
-            )
-            is_true(
-                element.compare(SelectStatementGrouping(select(t)).subquery())
-            )
+            expect(roles.FromClauseRole, SelectStatementGrouping(select(t)))
 
     def test_offset_or_limit_role_only_ints_or_clauseelement(self):
         assert_raises(ValueError, select(t).limit, "some limit")
@@ -310,22 +306,20 @@ class RoleTest(fixtures.TestBase):
         d1 = DDL("hi")
         is_(expect(roles.StatementRole, d1), d1)
 
-    def test_strict_from_clause_role(self):
+    def test_from_clause_role(self):
         stmt = select(t).subquery()
         is_true(
-            expect(roles.StrictFromClauseRole, stmt).compare(
-                select(t).subquery()
-            )
+            expect(roles.FromClauseRole, stmt).compare(select(t).subquery())
         )
 
-    def test_strict_from_clause_role_disallow_select(self):
+    def test_from_clause_role_disallow_select(self):
         stmt = select(t)
         assert_raises_message(
             exc.ArgumentError,
             r"FROM expression, such as a Table or alias\(\) "
             "object expected, got .*Select",
             expect,
-            roles.StrictFromClauseRole,
+            roles.FromClauseRole,
             stmt,
         )
 
@@ -402,6 +396,24 @@ class SubqueryCoercionsTest(fixtures.TestBase, AssertsCompiledSQL):
                 coerced = coercions.expect(role, stmt.alias())
                 is_true(coerced.compare(stmt.scalar_subquery()))
 
+    def test_fromclause_subquery(self):
+        stmt = select(self.table1.c.myid)
+        with expect_raises_message(
+            exc.ArgumentError,
+            r"FROM expression, such as a Table or alias\(\) object expected",
+        ):
+            coercions.expect(roles.FromClauseRole, stmt)
+
+    def test_plain_fromclause_select_to_subquery(self):
+        with expect_raises_message(
+            exc.ArgumentError,
+            r"FROM expression, such as a Table or alias\(\) object expected",
+        ):
+            coercions.expect(
+                roles.FromClauseRole,
+                SelectStatementGrouping(select(self.table1)),
+            )
+
     def test_labeled_role(self):
         stmt = select(self.table1.c.myid)
 
index 4a252930a38d9cf62d231dd28acc0cd907aa7eb6..c2f07444b883bbb37f1a7a4ac7870e92d4197216 100644 (file)
@@ -1575,24 +1575,6 @@ class SelectableTest(
             "SELECT table1.col1 AS a FROM table1) AS b) AS c) AS anon_1",
         )
 
-    def test_self_referential_select_raises(self):
-        t = table("t", column("x"))
-
-        # this issue is much less likely as subquery() applies a labeling
-        # style to the select, eliminating the self-referential call unless
-        # the select already had labeling applied
-
-        s = select(t).set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
-
-        with testing.expect_deprecated("The SelectBase.c"):
-            s.where.non_generative(s, s.c.t_x > 5)
-
-        assert_raises_message(
-            exc.InvalidRequestError,
-            r"select\(\) construct refers to itself as a FROM",
-            s.compile,
-        )
-
     def test_unusual_column_elements_text(self):
         """test that .c excludes text()."""