diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2023-01-19 15:34:46 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2023-01-20 09:13:58 -0500 |
commit | d1eeef5e67fa4632f88a894f0c5cf4445f04ba2b (patch) | |
tree | 30f2ad05dbf45bb2aa5dc33502a24cbdc5281097 /lib/sqlalchemy/sql/elements.py | |
parent | e82a5f19e1606500ad4bf6a456c2558d74df24bf (diff) | |
download | sqlalchemy-d1eeef5e67fa4632f88a894f0c5cf4445f04ba2b.tar.gz |
typing updates
The :meth:`_sql.ColumnOperators.in_` and
:meth:`_sql.ColumnOperators.not_in_` are typed to include
``Iterable[Any]`` rather than ``Sequence[Any]`` for more flexibility in
argument type.
The :func:`_sql.or_` and :func:`_sql.and_` from a typing perspective
require the first argument to be present, however these functions still
accept zero arguments which will emit a deprecation warning at runtime.
Typing is also added to support sending the fixed literal ``False`` for
:func:`_sql.or_` and ``True`` for :func:`_sql.and_` as the first argument
only, however the documentation now indicates sending the
:func:`_sql.false` and :func:`_sql.true` constructs in these cases as a
more explicit approach.
Fixed typing issue where iterating over a :class:`_orm.Query` object
was not correctly typed.
Fixes: #9122
Fixes: #9123
Fixes: #9125
Change-Id: I500e3e1b826717b3dd49afa1e682c3c8279c9226
Diffstat (limited to 'lib/sqlalchemy/sql/elements.py')
-rw-r--r-- | lib/sqlalchemy/sql/elements.py | 75 |
1 files changed, 49 insertions, 26 deletions
diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py index 6d1949425..981f71964 100644 --- a/lib/sqlalchemy/sql/elements.py +++ b/lib/sqlalchemy/sql/elements.py @@ -863,7 +863,7 @@ class SQLCoreOperations(Generic[_T], ColumnOperators, TypingOnly): def in_( self, other: Union[ - Sequence[Any], BindParameter[Any], roles.InElementRole + Iterable[Any], BindParameter[Any], roles.InElementRole ], ) -> BinaryExpression[bool]: ... @@ -871,7 +871,7 @@ class SQLCoreOperations(Generic[_T], ColumnOperators, TypingOnly): def not_in( self, other: Union[ - Sequence[Any], BindParameter[Any], roles.InElementRole + Iterable[Any], BindParameter[Any], roles.InElementRole ], ) -> BinaryExpression[bool]: ... @@ -2944,16 +2944,39 @@ class BooleanClauseList(ExpressionClauseList[bool]): operator: OperatorType, continue_on: Any, skip_on: Any, - *clauses: _ColumnExpressionArgument[Any], + initial_clause: Any = _NoArg.NO_ARG, + *clauses: Any, **kw: Any, ) -> ColumnElement[Any]: + + if initial_clause is _NoArg.NO_ARG: + # no elements period. deprecated use case. return an empty + # ClauseList construct that generates nothing unless it has + # elements added to it. + name = operator.__name__ + + util.warn_deprecated( + f"Invoking {name}() without arguments is deprecated, and " + f"will be disallowed in a future release. For an empty " + f"""{name}() construct, use '{name}({ + 'true()' if continue_on is True_._singleton else 'false()' + }, *args)' """ + f"""or '{name}({ + 'True' if continue_on is True_._singleton else 'False' + }, *args)'.""", + version="1.4", + ) + return cls._construct_raw(operator) # type: ignore[no-any-return] + lcc, convert_clauses = cls._process_clauses_for_boolean( operator, continue_on, skip_on, [ coercions.expect(roles.WhereHavingRole, clause) - for clause in util.coerce_generator_arg(clauses) + for clause in util.coerce_generator_arg( + (initial_clause,) + clauses + ) ], ) @@ -2969,27 +2992,11 @@ class BooleanClauseList(ExpressionClauseList[bool]): ) return cls._construct_raw(operator, flattened_clauses) # type: ignore # noqa: E501 - elif lcc == 1: + else: + assert lcc # just one element. return it as a single boolean element, # not a list and discard the operator. return convert_clauses[0] # type: ignore[no-any-return] # noqa: E501 - else: - # no elements period. deprecated use case. return an empty - # ClauseList construct that generates nothing unless it has - # elements added to it. - util.warn_deprecated( - "Invoking %(name)s() without arguments is deprecated, and " - "will be disallowed in a future release. For an empty " - "%(name)s() construct, use %(name)s(%(continue_on)s, *args)." - % { - "name": operator.__name__, - "continue_on": "True" - if continue_on is True_._singleton - else "False", - }, - version="1.4", - ) - return cls._construct_raw(operator) # type: ignore[no-any-return] # noqa: E501 @classmethod def _construct_for_whereclause( @@ -3035,26 +3042,42 @@ class BooleanClauseList(ExpressionClauseList[bool]): @classmethod def and_( - cls, *clauses: _ColumnExpressionArgument[bool] + cls, + initial_clause: Union[ + Literal[True], _ColumnExpressionArgument[bool], _NoArg + ] = _NoArg.NO_ARG, + *clauses: _ColumnExpressionArgument[bool], ) -> ColumnElement[bool]: r"""Produce a conjunction of expressions joined by ``AND``. See :func:`_sql.and_` for full documentation. """ return cls._construct( - operators.and_, True_._singleton, False_._singleton, *clauses + operators.and_, + True_._singleton, + False_._singleton, + initial_clause, + *clauses, ) @classmethod def or_( - cls, *clauses: _ColumnExpressionArgument[bool] + cls, + initial_clause: Union[ + Literal[False], _ColumnExpressionArgument[bool], _NoArg + ] = _NoArg.NO_ARG, + *clauses: _ColumnExpressionArgument[bool], ) -> ColumnElement[bool]: """Produce a conjunction of expressions joined by ``OR``. See :func:`_sql.or_` for full documentation. """ return cls._construct( - operators.or_, False_._singleton, True_._singleton, *clauses + operators.or_, + False_._singleton, + True_._singleton, + initial_clause, + *clauses, ) @property |