summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql/elements.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2023-01-19 15:34:46 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2023-01-20 09:13:58 -0500
commitd1eeef5e67fa4632f88a894f0c5cf4445f04ba2b (patch)
tree30f2ad05dbf45bb2aa5dc33502a24cbdc5281097 /lib/sqlalchemy/sql/elements.py
parente82a5f19e1606500ad4bf6a456c2558d74df24bf (diff)
downloadsqlalchemy-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.py75
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