From: Mike Bayer Date: Wed, 29 Dec 2021 17:10:23 +0000 (-0500) Subject: remove legacy select patterns X-Git-Tag: rel_2_0_0b1~570^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=97d81d346fe624e7bee818dc7ac9ca00ec343f6d;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git remove legacy select patterns Change-Id: If6e521a1eb461e08748a0432943b938528a2619e References: #7257 --- diff --git a/doc/build/changelog/unreleased_20/7257.rst b/doc/build/changelog/unreleased_20/7257.rst index c06ef4f0d7..3600c3321b 100644 --- a/doc/build/changelog/unreleased_20/7257.rst +++ b/doc/build/changelog/unreleased_20/7257.rst @@ -34,4 +34,8 @@ long-documented approach of using ``Class.attrname`` for loader option targets is now standard. + * Legacy forms of :func:`_sql.select` removed, including + ``select([cols])``, the "whereclause" and keyword parameters of + ``some_table.select()``. + * More are in progress as development continues diff --git a/lib/sqlalchemy/__init__.py b/lib/sqlalchemy/__init__.py index 79ad873507..3e1aeac4ec 100644 --- a/lib/sqlalchemy/__init__.py +++ b/lib/sqlalchemy/__init__.py @@ -73,7 +73,6 @@ from .sql import outerjoin from .sql import outparam from .sql import over from .sql import select -from .sql import subquery from .sql import table from .sql import tablesample from .sql import text diff --git a/lib/sqlalchemy/future/__init__.py b/lib/sqlalchemy/future/__init__.py index 9bf4d042df..0bd74c25a1 100644 --- a/lib/sqlalchemy/future/__init__.py +++ b/lib/sqlalchemy/future/__init__.py @@ -15,4 +15,4 @@ from ..sql.selectable import Select from ..util.langhelpers import public_factory -select = public_factory(Select._create_future_select, ".future.select") +select = public_factory(Select._create, ".future.select") diff --git a/lib/sqlalchemy/sql/__init__.py b/lib/sqlalchemy/sql/__init__.py index f374d555d5..20f0505f52 100644 --- a/lib/sqlalchemy/sql/__init__.py +++ b/lib/sqlalchemy/sql/__init__.py @@ -73,7 +73,6 @@ from .expression import select from .expression import Selectable from .expression import StatementLambdaElement from .expression import Subquery -from .expression import subquery from .expression import table from .expression import TableClause from .expression import TableSample diff --git a/lib/sqlalchemy/sql/coercions.py b/lib/sqlalchemy/sql/coercions.py index 9b8b4540c2..fa21fbeeff 100644 --- a/lib/sqlalchemy/sql/coercions.py +++ b/lib/sqlalchemy/sql/coercions.py @@ -418,9 +418,13 @@ class LiteralValueImpl(RoleImpl): class _SelectIsNotFrom: __slots__ = () - def _raise_for_expected(self, element, argname=None, resolved=None, **kw): - if isinstance(element, roles.SelectStatementRole) or isinstance( - resolved, roles.SelectStatementRole + def _raise_for_expected( + self, element, argname=None, resolved=None, advice=None, **kw + ): + if ( + not advice + and isinstance(element, roles.SelectStatementRole) + or isinstance(resolved, roles.SelectStatementRole) ): advice = ( "To create a " @@ -429,7 +433,7 @@ class _SelectIsNotFrom: ) code = "89ve" else: - advice = code = None + code = None return super(_SelectIsNotFrom, self)._raise_for_expected( element, @@ -815,6 +819,19 @@ class ColumnsClauseImpl(_SelectIsNotFrom, _CoerceLiterals, RoleImpl): _guess_straight_column = re.compile(r"^\w\S*$", re.I) + def _raise_for_expected( + self, element, argname=None, resolved=None, advice=None, **kw + ): + if not advice and isinstance(element, list): + advice = ( + f"Did you mean to say select(" + f"{', '.join(repr(e) for e in element)})?" + ) + + return super(ColumnsClauseImpl, self)._raise_for_expected( + element, argname=argname, resolved=resolved, advice=advice, **kw + ) + def _text_coercion(self, element, argname=None): element = str(element) diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index 03fe9b567c..407f1dd33f 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -7,10 +7,6 @@ """Defines the public namespace for SQL expression constructs. -Prior to version 0.9, this module contained all of "elements", "dml", -"default_comparator" and "selectable". The module was broken up -and most "factory" functions were moved to be grouped with their associated -class. """ @@ -169,7 +165,6 @@ from .selectable import Select from .selectable import Selectable from .selectable import SelectBase from .selectable import Subquery -from .selectable import subquery from .selectable import TableClause from .selectable import TableSample from .selectable import TableValuedAlias diff --git a/lib/sqlalchemy/sql/functions.py b/lib/sqlalchemy/sql/functions.py index 5d2e780653..fa0b06421b 100644 --- a/lib/sqlalchemy/sql/functions.py +++ b/lib/sqlalchemy/sql/functions.py @@ -8,6 +8,7 @@ """SQL function API, factories, and built-in functions. """ + from . import annotation from . import coercions from . import operators @@ -557,7 +558,7 @@ class FunctionElement(Executable, ColumnElement, FromClause, Generative): self, name, table_value_type=self.type ) - def select(self): + def select(self) -> "Select": """Produce a :func:`_expression.select` construct against this :class:`.FunctionElement`. @@ -566,7 +567,7 @@ class FunctionElement(Executable, ColumnElement, FromClause, Generative): s = select(function_element) """ - s = Select._create_select(self) + s = Select._create(self) if self._execution_options: s = s.execution_options(**self._execution_options) return s diff --git a/lib/sqlalchemy/sql/selectable.py b/lib/sqlalchemy/sql/selectable.py index 2f157c27e0..802576b899 100644 --- a/lib/sqlalchemy/sql/selectable.py +++ b/lib/sqlalchemy/sql/selectable.py @@ -58,7 +58,6 @@ from .elements import UnaryExpression from .visitors import InternalTraversal from .. import exc from .. import util -from ..inspection import inspect class _OffsetLimitParam(BindParameter): @@ -69,24 +68,6 @@ class _OffsetLimitParam(BindParameter): return self.effective_value -@util.deprecated( - "1.4", - "The standalone :func:`.subquery` function is deprecated " - "and will be removed in a future release. Use select().subquery().", -) -def subquery(alias, *args, **kwargs): - r"""Return an :class:`.Subquery` object derived - from a :class:`_expression.Select`. - - :param alias: the alias name for the subquery - - :param \*args, \**kwargs: all other arguments are passed through to the - :func:`_expression.select` function. - - """ - return Select.create_legacy_select(*args, **kwargs).subquery(alias) - - class ReturnsRows(roles.ReturnsRowsRole, ClauseElement): """The base-most class for Core constructs that have some concept of columns that can represent rows. @@ -459,25 +440,7 @@ class FromClause(roles.AnonymizedFromClauseRole, Selectable): _use_schema_map = False - @util.deprecated_params( - whereclause=( - "2.0", - "The :paramref:`_sql.FromClause.select().whereclause` parameter " - "is deprecated and will be removed in version 2.0. " - "Please make use of " - "the :meth:`.Select.where` " - "method to add WHERE criteria to the SELECT statement.", - ), - kwargs=( - "2.0", - "The :meth:`_sql.FromClause.select` method will no longer accept " - "keyword arguments in version 2.0. Please use generative methods " - "from the " - ":class:`_sql.Select` construct in order to apply additional " - "modifications.", - ), - ) - def select(self, whereclause=None, **kwargs): + def select(self) -> "Select": r"""Return a SELECT of this :class:`_expression.FromClause`. @@ -485,22 +448,13 @@ class FromClause(roles.AnonymizedFromClauseRole, Selectable): stmt = some_table.select().where(some_table.c.id == 5) - :param whereclause: a WHERE clause, equivalent to calling the - :meth:`_sql.Select.where` method. - - :param \**kwargs: additional keyword arguments are passed to the - legacy constructor for :class:`_sql.Select` described at - :meth:`_sql.Select.create_legacy_select`. - .. seealso:: :func:`_expression.select` - general purpose method which allows for arbitrary column lists. """ - if whereclause is not None: - kwargs["whereclause"] = whereclause - return Select._create_select_from_fromclause(self, [self], **kwargs) + return Select._create(self) def join(self, right, onclause=None, isouter=False, full=False): """Return a :class:`_expression.Join` from this @@ -1343,25 +1297,7 @@ class Join(roles.DMLTableRole, FromClause): "join explicitly." % (a.description, b.description) ) - @util.deprecated_params( - whereclause=( - "2.0", - "The :paramref:`_sql.Join.select().whereclause` parameter " - "is deprecated and will be removed in version 2.0. " - "Please make use of " - "the :meth:`.Select.where` " - "method to add WHERE criteria to the SELECT statement.", - ), - kwargs=( - "2.0", - "The :meth:`_sql.Join.select` method will no longer accept " - "keyword arguments in version 2.0. Please use generative " - "methods from the " - ":class:`_sql.Select` construct in order to apply additional " - "modifications.", - ), - ) - def select(self, whereclause=None, **kwargs): + def select(self) -> "Select": r"""Create a :class:`_expression.Select` from this :class:`_expression.Join`. @@ -1376,21 +1312,8 @@ class Join(roles.DMLTableRole, FromClause): SELECT table_a.id, table_a.col, table_b.id, table_b.a_id FROM table_a JOIN table_b ON table_a.id = table_b.a_id - :param whereclause: WHERE criteria, same as calling - :meth:`_sql.Select.where` on the resulting statement - - :param \**kwargs: additional keyword arguments are passed to the - legacy constructor for :class:`_sql.Select` described at - :meth:`_sql.Select.create_legacy_select`. - """ - collist = [self.left, self.right] - - if whereclause is not None: - kwargs["whereclause"] = whereclause - return Select._create_select_from_fromclause( - self, collist, **kwargs - ).select_from(self) + return Select._create(self.left, self.right).select_from(self) @util.preload_module("sqlalchemy.sql.util") def _anonymous_fromclause(self, name=None, flat=False): @@ -4814,278 +4737,9 @@ class Select( ] @classmethod - def _create_select_from_fromclause(cls, target, entities, *arg, **kw): - if arg or kw: - return Select.create_legacy_select(entities, *arg, **kw) - else: - return Select._create_select(*entities) - - @classmethod - @util.deprecated( - "2.0", - "The legacy calling style of :func:`_sql.select` is deprecated and " - "will be removed in SQLAlchemy 2.0. Please use the new calling " - "style described at :func:`_sql.select`.", - ) - def create_legacy_select( - cls, - columns=None, - whereclause=None, - from_obj=None, - distinct=False, - having=None, - correlate=True, - prefixes=None, - suffixes=None, - **kwargs - ): - """Construct a new :class:`_expression.Select` using the 1.x style API. - - This method is called implicitly when the :func:`_expression.select` - construct is used and the first argument is a Python list or other - plain sequence object, which is taken to refer to the columns - collection. - - .. versionchanged:: 1.4 Added the :meth:`.Select.create_legacy_select` - constructor which documents the calling style in use when the - :func:`.select` construct is invoked using 1.x-style arguments. - - Similar functionality is also available via the - :meth:`_expression.FromClause.select` method on any - :class:`_expression.FromClause`. - - All arguments which accept :class:`_expression.ClauseElement` arguments - also accept string arguments, which will be converted as appropriate - into either :func:`_expression.text()` or - :func:`_expression.literal_column()` constructs. - - .. seealso:: - - :ref:`coretutorial_selecting` - Core Tutorial description of - :func:`_expression.select`. - - :param columns: - A list of :class:`_expression.ColumnElement` or - :class:`_expression.FromClause` - objects which will form the columns clause of the resulting - statement. For those objects that are instances of - :class:`_expression.FromClause` (typically :class:`_schema.Table` - or :class:`_expression.Alias` - objects), the :attr:`_expression.FromClause.c` - collection is extracted - to form a collection of :class:`_expression.ColumnElement` objects. - - This parameter will also accept :class:`_expression.TextClause` - constructs as - given, as well as ORM-mapped classes. - - .. note:: - - The :paramref:`_expression.select.columns` - parameter is not available - in the method form of :func:`_expression.select`, e.g. - :meth:`_expression.FromClause.select`. - - .. seealso:: - - :meth:`_expression.Select.column` - - :meth:`_expression.Select.with_only_columns` - - :param whereclause: - A :class:`_expression.ClauseElement` - expression which will be used to form the - ``WHERE`` clause. It is typically preferable to add WHERE - criterion to an existing :class:`_expression.Select` - using method chaining - with :meth:`_expression.Select.where`. - - .. seealso:: - - :meth:`_expression.Select.where` - - :param from_obj: - A list of :class:`_expression.ClauseElement` - objects which will be added to the - ``FROM`` clause of the resulting statement. This is equivalent - to calling :meth:`_expression.Select.select_from` - using method chaining on - an existing :class:`_expression.Select` object. - - .. seealso:: - - :meth:`_expression.Select.select_from` - - full description of explicit - FROM clause specification. - - :param correlate=True: - indicates that this :class:`_expression.Select` - object should have its - contained :class:`_expression.FromClause` - elements "correlated" to an enclosing - :class:`_expression.Select` object. - It is typically preferable to specify - correlations on an existing :class:`_expression.Select` - construct using - :meth:`_expression.Select.correlate`. - - .. seealso:: - - :meth:`_expression.Select.correlate` - - full description of correlation. - - :param distinct=False: - when ``True``, applies a ``DISTINCT`` qualifier to the columns - clause of the resulting statement. - - The boolean argument may also be a column expression or list - of column expressions - this is a special calling form which - is understood by the PostgreSQL dialect to render the - ``DISTINCT ON ()`` syntax. - - ``distinct`` is also available on an existing - :class:`_expression.Select` - object via the :meth:`_expression.Select.distinct` method. - - .. seealso:: - - :meth:`_expression.Select.distinct` - - :param group_by: - a list of :class:`_expression.ClauseElement` - objects which will comprise the - ``GROUP BY`` clause of the resulting select. This parameter - is typically specified more naturally using the - :meth:`_expression.Select.group_by` method on an existing - :class:`_expression.Select`. - - .. seealso:: - - :meth:`_expression.Select.group_by` - - :param having: - a :class:`_expression.ClauseElement` - that will comprise the ``HAVING`` clause - of the resulting select when ``GROUP BY`` is used. This parameter - is typically specified more naturally using the - :meth:`_expression.Select.having` method on an existing - :class:`_expression.Select`. - - .. seealso:: - - :meth:`_expression.Select.having` + def _create(cls, *entities) -> "Select": + r"""Construct a new :class:`_expression.Select`. - :param limit=None: - a numerical value which usually renders as a ``LIMIT`` - expression in the resulting select. Backends that don't - support ``LIMIT`` will attempt to provide similar - functionality. This parameter is typically specified more - naturally using the :meth:`_expression.Select.limit` - method on an existing - :class:`_expression.Select`. - - .. seealso:: - - :meth:`_expression.Select.limit` - - :param offset=None: - a numeric value which usually renders as an ``OFFSET`` - expression in the resulting select. Backends that don't - support ``OFFSET`` will attempt to provide similar - functionality. This parameter is typically specified more naturally - using the :meth:`_expression.Select.offset` method on an existing - :class:`_expression.Select`. - - .. seealso:: - - :meth:`_expression.Select.offset` - - :param order_by: - a scalar or list of :class:`_expression.ClauseElement` - objects which will - comprise the ``ORDER BY`` clause of the resulting select. - This parameter is typically specified more naturally using the - :meth:`_expression.Select.order_by` method on an existing - :class:`_expression.Select`. - - .. seealso:: - - :meth:`_expression.Select.order_by` - - :param use_labels=False: - when ``True``, the statement will be generated using labels - for each column in the columns clause, which qualify each - column with its parent table's (or aliases) name so that name - conflicts between columns in different tables don't occur. - The format of the label is ``_``. The "c" - collection of a :class:`_expression.Subquery` created - against this :class:`_expression.Select` - object, as well as the :attr:`_expression.Select.selected_columns` - collection of the :class:`_expression.Select` itself, will use these - names for targeting column members. - - This parameter can also be specified on an existing - :class:`_expression.Select` object using the - :meth:`_expression.Select.set_label_style` - method. - - .. seealso:: - - :meth:`_expression.Select.set_label_style` - - """ - self = cls.__new__(cls) - - self._auto_correlate = correlate - - if distinct is not False: - if distinct is True: - self.distinct.non_generative(self) - else: - self.distinct.non_generative(self, *util.to_list(distinct)) - - if from_obj is not None: - self.select_from.non_generative(self, *util.to_list(from_obj)) - - try: - cols_present = bool(columns) - except TypeError as err: - raise exc.ArgumentError( - "select() construct created in legacy mode, i.e. with " - "keyword arguments, must provide the columns argument as " - "a Python list or other iterable.", - code="c9ae", - ) from err - - if cols_present: - self._raw_columns = [ - coercions.expect( - roles.ColumnsClauseRole, c, apply_propagate_attrs=self - ) - for c in columns - ] - else: - self._raw_columns = [] - - if whereclause is not None: - self.where.non_generative(self, whereclause) - - if having is not None: - self.having.non_generative(self, having) - - if prefixes: - self._setup_prefixes(prefixes) - - if suffixes: - self._setup_suffixes(suffixes) - - GenerativeSelect.__init__(self, **kwargs) - return self - - @classmethod - def _create_future_select(cls, *entities): - r"""Construct a new :class:`_expression.Select` using the 2. - x style API. .. versionadded:: 1.4 - The :func:`_sql.select` function now accepts column arguments positionally. The top-level :func:`_sql.select` @@ -5133,8 +4787,6 @@ class Select( return self - _create_select = _create_future_select - @classmethod def _create_raw_select(cls, **kw): """Create a :class:`.Select` using raw ``__new__`` with no coercions. @@ -5148,62 +4800,6 @@ class Select( stmt.__dict__.update(kw) return stmt - @classmethod - def _create(cls, *args, **kw): - r"""Create a :class:`.Select` using either the 1.x or 2.0 constructor - style. - - For the legacy calling style, see :meth:`.Select.create_legacy_select`. - If the first argument passed is a Python sequence or if keyword - arguments are present, this style is used. - - .. versionadded:: 2.0 - the :func:`_future.select` construct is - the same construct as the one returned by - :func:`_expression.select`, except that the function only - accepts the "columns clause" entities up front; the rest of the - state of the SELECT should be built up using generative methods. - - Similar functionality is also available via the - :meth:`_expression.FromClause.select` method on any - :class:`_expression.FromClause`. - - .. seealso:: - - :ref:`coretutorial_selecting` - Core Tutorial description of - :func:`_expression.select`. - - :param \*entities: - Entities to SELECT from. For Core usage, this is typically a series - of :class:`_expression.ColumnElement` and / or - :class:`_expression.FromClause` - objects which will form the columns clause of the resulting - statement. For those objects that are instances of - :class:`_expression.FromClause` (typically :class:`_schema.Table` - or :class:`_expression.Alias` - objects), the :attr:`_expression.FromClause.c` - collection is extracted - to form a collection of :class:`_expression.ColumnElement` objects. - - This parameter will also accept :class:`_expression.TextClause` - constructs as given, as well as ORM-mapped classes. - - """ - if ( - args - and ( - isinstance(args[0], list) - or ( - hasattr(args[0], "__iter__") - and not isinstance(args[0], (str, ClauseElement)) - and inspect(args[0], raiseerr=False) is None - and not hasattr(args[0], "__clause_element__") - ) - ) - ) or kw: - return cls.create_legacy_select(*args, **kw) - else: - return cls._create_future_select(*args) - def __init__(self): raise NotImplementedError() @@ -6549,25 +6145,7 @@ class Exists(UnaryExpression): element = fn(element) return element.self_group(against=operators.exists) - @util.deprecated_params( - whereclause=( - "2.0", - "The :paramref:`_sql.Exists.select().whereclause` parameter " - "is deprecated and will be removed in version 2.0. " - "Please make use " - "of the :meth:`.Select.where` " - "method to add WHERE criteria to the SELECT statement.", - ), - kwargs=( - "2.0", - "The :meth:`_sql.Exists.select` method will no longer accept " - "keyword arguments in version 2.0. " - "Please use generative methods from the " - ":class:`_sql.Select` construct in order to apply additional " - "modifications.", - ), - ) - def select(self, whereclause=None, **kwargs): + def select(self) -> "Select": r"""Return a SELECT of this :class:`_expression.Exists`. e.g.:: @@ -6578,13 +6156,6 @@ class Exists(UnaryExpression): SELECT EXISTS (SELECT id FROM some_table WHERE some_table = :param) AS anon_1 - :param whereclause: a WHERE clause, equivalent to calling the - :meth:`_sql.Select.where` method. - - :param **kwargs: additional keyword arguments are passed to the - legacy constructor for :class:`_sql.Select` described at - :meth:`_sql.Select.create_legacy_select`. - .. seealso:: :func:`_expression.select` - general purpose @@ -6592,9 +6163,7 @@ class Exists(UnaryExpression): """ # noqa - if whereclause is not None: - kwargs["whereclause"] = whereclause - return Select._create_select_from_fromclause(self, [self], **kwargs) + return Select._create(self) def correlate(self, *fromclause): """Apply correlation to the subquery noted by this :class:`_sql.Exists`. diff --git a/test/sql/test_deprecations.py b/test/sql/test_deprecations.py index cd0b0f2c36..1a839a5f82 100644 --- a/test/sql/test_deprecations.py +++ b/test/sql/test_deprecations.py @@ -10,7 +10,6 @@ from sqlalchemy import case from sqlalchemy import CHAR from sqlalchemy import column from sqlalchemy import exc -from sqlalchemy import exists from sqlalchemy import ForeignKey from sqlalchemy import func from sqlalchemy import Integer @@ -36,7 +35,6 @@ from sqlalchemy.sql import quoted_name from sqlalchemy.sql import roles from sqlalchemy.sql import update from sqlalchemy.sql import visitors -from sqlalchemy.sql.selectable import LABEL_STYLE_NONE from sqlalchemy.sql.selectable import SelectStatementGrouping from sqlalchemy.testing import assert_raises_message from sqlalchemy.testing import assertions @@ -315,156 +313,6 @@ class SelectableTest(fixtures.TestBase, AssertsCompiledSQL): ): eq_(stmt.froms, [t1]) - def test_select_list_argument(self): - - with testing.expect_deprecated_20( - r"The legacy calling style of select\(\) is deprecated " - "and will be removed in SQLAlchemy 2.0" - ): - stmt = select([column("q")]) - self.assert_compile(stmt, "SELECT q") - - def test_select_column_collection_argument(self): - t1 = table("t1", column("q")) - - with testing.expect_deprecated_20( - r"The legacy calling style of select\(\) is deprecated " - "and will be removed in SQLAlchemy 2.0" - ): - stmt = select(t1.c) - self.assert_compile(stmt, "SELECT t1.q FROM t1") - - def test_select_kw_argument(self): - - with testing.expect_deprecated_20( - r"The legacy calling style of select\(\) is deprecated " - "and will be removed in SQLAlchemy 2.0" - ): - stmt = select(whereclause=column("q") == 5).add_columns( - column("q") - ) - self.assert_compile(stmt, "SELECT q WHERE q = :q_1") - - @testing.combinations( - ( - lambda table1: table1.select(table1.c.col1 == 5), - "FromClause", - "whereclause", - "SELECT table1.col1, table1.col2, table1.col3, table1.colx " - "FROM table1 WHERE table1.col1 = :col1_1", - ), - ( - lambda table1: table1.select(whereclause=table1.c.col1 == 5), - "FromClause", - "whereclause", - "SELECT table1.col1, table1.col2, table1.col3, table1.colx " - "FROM table1 WHERE table1.col1 = :col1_1", - ), - ( - lambda table1: table1.select(order_by=table1.c.col1), - "FromClause", - "kwargs", - "SELECT table1.col1, table1.col2, table1.col3, table1.colx " - "FROM table1 ORDER BY table1.col1", - ), - ( - lambda table1: exists().select(table1.c.col1 == 5), - "Exists", - "whereclause", - "SELECT EXISTS (SELECT *) AS anon_1 FROM table1 " - "WHERE table1.col1 = :col1_1", - ), - ( - lambda table1: exists().select(whereclause=table1.c.col1 == 5), - "Exists", - "whereclause", - "SELECT EXISTS (SELECT *) AS anon_1 FROM table1 " - "WHERE table1.col1 = :col1_1", - ), - ( - lambda table1: exists().select( - order_by=table1.c.col1, from_obj=table1 - ), - "Exists", - "kwargs", - "SELECT EXISTS (SELECT *) AS anon_1 FROM table1 " - "ORDER BY table1.col1", - ), - ( - lambda table1, table2: table1.join(table2) - .select(table1.c.col1 == 5) - .set_label_style(LABEL_STYLE_NONE), - "Join", - "whereclause", - "SELECT table1.col1, table1.col2, table1.col3, table1.colx, " - "table2.col1, table2.col2, table2.col3, table2.coly FROM table1 " - "JOIN table2 ON table1.col1 = table2.col2 " - "WHERE table1.col1 = :col1_1", - ), - ( - lambda table1, table2: table1.join(table2) - .select(whereclause=table1.c.col1 == 5) - .set_label_style(LABEL_STYLE_NONE), - "Join", - "whereclause", - "SELECT table1.col1, table1.col2, table1.col3, table1.colx, " - "table2.col1, table2.col2, table2.col3, table2.coly FROM table1 " - "JOIN table2 ON table1.col1 = table2.col2 " - "WHERE table1.col1 = :col1_1", - ), - ( - lambda table1, table2: table1.join(table2) - .select(order_by=table1.c.col1) - .set_label_style(LABEL_STYLE_NONE), - "Join", - "kwargs", - "SELECT table1.col1, table1.col2, table1.col3, table1.colx, " - "table2.col1, table2.col2, table2.col3, table2.coly FROM table1 " - "JOIN table2 ON table1.col1 = table2.col2 " - "ORDER BY table1.col1", - ), - ) - def test_select_method_parameters( - self, stmt, clsname, paramname, expected_sql - ): - if paramname == "whereclause": - warning_txt = ( - r"The %s.select\(\).whereclause parameter is deprecated " - "and will be removed in version 2.0" % clsname - ) - else: - warning_txt = ( - r"The %s.select\(\) method will no longer accept " - "keyword arguments in version 2.0. " % clsname - ) - with testing.expect_deprecated_20( - warning_txt, - r"The legacy calling style of select\(\) is deprecated " - "and will be removed in SQLAlchemy 2.0", - ): - stmt = testing.resolve_lambda( - stmt, table1=self.table1, table2=self.table2 - ) - - self.assert_compile(stmt, expected_sql) - - def test_deprecated_subquery_standalone(self): - from sqlalchemy import subquery - - with testing.expect_deprecated( - r"The standalone subquery\(\) function is deprecated" - ): - stmt = subquery( - None, - [literal_column("1").label("a")], - order_by=literal_column("1"), - ) - - self.assert_compile( - select(stmt), - "SELECT anon_1.a FROM (SELECT 1 AS a ORDER BY 1) AS anon_1", - ) - def test_case_list_legacy(self): t1 = table("t", column("q")) @@ -1681,64 +1529,3 @@ class FutureSelectTest(fixtures.TestBase, AssertsCompiledSQL): column("othername", String), ) return table1, table2 - - def test_legacy_calling_style_kw_only(self, table_fixture): - table1, table2 = table_fixture - with testing.expect_deprecated_20( - "The legacy calling style of select" - ): - stmt = select( - whereclause=table1.c.myid == table2.c.otherid - ).add_columns(table1.c.myid) - - self.assert_compile( - stmt, - "SELECT mytable.myid FROM mytable, myothertable " - "WHERE mytable.myid = myothertable.otherid", - ) - - def test_legacy_calling_style_col_seq_only(self, table_fixture): - table1, table2 = table_fixture - with testing.expect_deprecated_20( - "The legacy calling style of select" - ): - # keep [] here - stmt = select([table1.c.myid]).where( - table1.c.myid == table2.c.otherid - ) - - self.assert_compile( - stmt, - "SELECT mytable.myid FROM mytable, myothertable " - "WHERE mytable.myid = myothertable.otherid", - ) - - def test_new_calling_style_thing_ok_actually_use_iter(self, table_fixture): - table1, table2 = table_fixture - - class Thing: - def __iter__(self): - return iter([table1.c.name, table1.c.description]) - - with testing.expect_deprecated_20( - "The legacy calling style of select" - ): - stmt = select(Thing()) - self.assert_compile( - stmt, - "SELECT mytable.name, mytable.description FROM mytable", - ) - - def test_kw_triggers_old_style(self, table_fixture): - table1, table2 = table_fixture - with testing.expect_deprecated_20( - "The legacy calling style of select" - ): - assert_raises_message( - exc.ArgumentError, - r"select\(\) construct created in legacy mode, " - "i.e. with keyword arguments", - select, - table1.c.myid, - whereclause=table1.c.myid == table2.c.otherid, - ) diff --git a/test/sql/test_select.py b/test/sql/test_select.py index f79d95a650..be64e205e4 100644 --- a/test/sql/test_select.py +++ b/test/sql/test_select.py @@ -16,6 +16,7 @@ from sqlalchemy.sql import literal from sqlalchemy.sql import table from sqlalchemy.testing import assert_raises_message from sqlalchemy.testing import AssertsCompiledSQL +from sqlalchemy.testing import expect_raises_message from sqlalchemy.testing import fixtures table1 = table( @@ -54,9 +55,17 @@ grandchild = Table( ) -class FutureSelectTest(fixtures.TestBase, AssertsCompiledSQL): +class SelectTest(fixtures.TestBase, AssertsCompiledSQL): __dialect__ = "default" + def test_old_bracket_style_fail(self): + with expect_raises_message( + exc.ArgumentError, + r"Column expression or FROM clause expected, " + r".*Did you mean to say", + ): + select([table1.c.myid]) + def test_new_calling_style(self): stmt = select(table1.c.myid).where(table1.c.myid == table2.c.otherid)