]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
add typing to legacy operators
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 26 Jan 2023 13:52:01 +0000 (08:52 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 26 Jan 2023 18:42:15 +0000 (13:42 -0500)
Added typing to legacy operators such as ``isnot()``, ``notin_()``, etc.
which previously were referencing the newer operators but were not
themselves typed.

Fixes: #9148
Change-Id: I3ad7d75d89ec13c9f45063033ecff69d610c72ca

doc/build/changelog/unreleased_20/more_typing.rst
lib/sqlalchemy/sql/elements.py
lib/sqlalchemy/sql/operators.py
test/ext/mypy/plain_files/sql_operations.py

index f7b1ba258da49b22fd9c4e11d0196007c1ad6b00..23f3cefdd127d31812183619b33faada926f2193 100644 (file)
     Fixed issue where using the :paramref:`_orm.relationship.remote_side`
     and similar parameters, passing an annotated declarative object typed as
     :class:`_orm.Mapped`, would not be accepted by the type checker.
+
+.. change::
+    :tags: typing, bug
+    :tickets: 9148
+
+    Added typing to legacy operators such as ``isnot()``, ``notin_()``, etc.
+    which previously were referencing the newer operators but were not
+    themselves typed.
index 05bc4ae89b622b9778e5d8d880968a95263f053a..71d8cb2d329a39f2134a4334921554d3d376965c 100644 (file)
@@ -876,22 +876,43 @@ class SQLCoreOperations(Generic[_T], ColumnOperators, TypingOnly):
         ) -> BinaryExpression[bool]:
             ...
 
+        def notin_(
+            self,
+            other: Union[
+                Iterable[Any], BindParameter[Any], roles.InElementRole
+            ],
+        ) -> BinaryExpression[bool]:
+            ...
+
         def not_like(
             self, other: Any, escape: Optional[str] = None
         ) -> BinaryExpression[bool]:
             ...
 
+        def notlike(
+            self, other: Any, escape: Optional[str] = None
+        ) -> BinaryExpression[bool]:
+            ...
+
         def not_ilike(
             self, other: Any, escape: Optional[str] = None
         ) -> BinaryExpression[bool]:
             ...
 
+        def notilike(
+            self, other: Any, escape: Optional[str] = None
+        ) -> BinaryExpression[bool]:
+            ...
+
         def is_(self, other: Any) -> BinaryExpression[bool]:
             ...
 
         def is_not(self, other: Any) -> BinaryExpression[bool]:
             ...
 
+        def isnot(self, other: Any) -> BinaryExpression[bool]:
+            ...
+
         def startswith(
             self,
             other: Any,
@@ -933,9 +954,15 @@ class SQLCoreOperations(Generic[_T], ColumnOperators, TypingOnly):
         def nulls_first(self) -> UnaryExpression[_T]:
             ...
 
+        def nullsfirst(self) -> UnaryExpression[_T]:
+            ...
+
         def nulls_last(self) -> UnaryExpression[_T]:
             ...
 
+        def nullslast(self) -> UnaryExpression[_T]:
+            ...
+
         def collate(self, collation: str) -> CollationClause:
             ...
 
index dc88b3e4968c745363993f02e77c0872cf9841d0..567802916fa1bf914938ac129d84a64b30b5af91 100644 (file)
@@ -42,6 +42,7 @@ from typing import Generic
 from typing import Optional
 from typing import Set
 from typing import Type
+from typing import TYPE_CHECKING
 from typing import TypeVar
 from typing import Union
 
@@ -557,7 +558,13 @@ class ColumnOperators(Operators):
         return self.operate(is_not_distinct_from, other)
 
     # deprecated 1.4; see #5435
-    isnot_distinct_from = is_not_distinct_from
+    if TYPE_CHECKING:
+
+        def isnot_distinct_from(self, other: Any) -> ColumnOperators:
+            ...
+
+    else:
+        isnot_distinct_from = is_not_distinct_from
 
     def __gt__(self, other: Any) -> ColumnOperators:
         """Implement the ``>`` operator.
@@ -808,7 +815,13 @@ class ColumnOperators(Operators):
         return self.operate(not_in_op, other)
 
     # deprecated 1.4; see #5429
-    notin_ = not_in
+    if TYPE_CHECKING:
+
+        def notin_(self, other: Any) -> ColumnOperators:
+            ...
+
+    else:
+        notin_ = not_in
 
     def not_like(
         self, other: Any, escape: Optional[str] = None
@@ -827,10 +840,18 @@ class ColumnOperators(Operators):
             :meth:`.ColumnOperators.like`
 
         """
-        return self.operate(notlike_op, other, escape=escape)
+        return self.operate(not_like_op, other, escape=escape)
 
     # deprecated 1.4; see #5435
-    notlike = not_like
+    if TYPE_CHECKING:
+
+        def notlike(
+            self, other: Any, escape: Optional[str] = None
+        ) -> ColumnOperators:
+            ...
+
+    else:
+        notlike = not_like
 
     def not_ilike(
         self, other: Any, escape: Optional[str] = None
@@ -849,10 +870,18 @@ class ColumnOperators(Operators):
             :meth:`.ColumnOperators.ilike`
 
         """
-        return self.operate(notilike_op, other, escape=escape)
+        return self.operate(not_ilike_op, other, escape=escape)
 
     # deprecated 1.4; see #5435
-    notilike = not_ilike
+    if TYPE_CHECKING:
+
+        def notilike(
+            self, other: Any, escape: Optional[str] = None
+        ) -> ColumnOperators:
+            ...
+
+    else:
+        notilike = not_ilike
 
     def is_(self, other: Any) -> ColumnOperators:
         """Implement the ``IS`` operator.
@@ -885,7 +914,13 @@ class ColumnOperators(Operators):
         return self.operate(is_not, other)
 
     # deprecated 1.4; see #5429
-    isnot = is_not
+    if TYPE_CHECKING:
+
+        def isnot(self, other: Any) -> ColumnOperators:
+            ...
+
+    else:
+        isnot = is_not
 
     def startswith(
         self,
@@ -1527,7 +1562,13 @@ class ColumnOperators(Operators):
         return self.operate(nulls_first_op)
 
     # deprecated 1.4; see #5435
-    nullsfirst = nulls_first
+    if TYPE_CHECKING:
+
+        def nullsfirst(self) -> ColumnOperators:
+            ...
+
+    else:
+        nullsfirst = nulls_first
 
     def nulls_last(self) -> ColumnOperators:
         """Produce a :func:`_expression.nulls_last` clause against the
@@ -1540,7 +1581,13 @@ class ColumnOperators(Operators):
         return self.operate(nulls_last_op)
 
     # deprecated 1.4; see #5429
-    nullslast = nulls_last
+    if TYPE_CHECKING:
+
+        def nullslast(self) -> ColumnOperators:
+            ...
+
+    else:
+        nullslast = nulls_last
 
     def collate(self, collation: str) -> ColumnOperators:
         """Produce a :func:`_expression.collate` clause against
@@ -1759,7 +1806,14 @@ def is_true(a: Any) -> Any:
 
 
 # 1.4 deprecated; see #5435
-istrue = is_true
+if TYPE_CHECKING:
+
+    @_operator_fn
+    def istrue(a: Any) -> Any:
+        ...
+
+else:
+    istrue = is_true
 
 
 @_operator_fn
@@ -1768,7 +1822,14 @@ def is_false(a: Any) -> Any:
 
 
 # 1.4 deprecated; see #5435
-isfalse = is_false
+if TYPE_CHECKING:
+
+    @_operator_fn
+    def isfalse(a: Any) -> Any:
+        ...
+
+else:
+    isfalse = is_false
 
 
 @comparison_op
@@ -1784,7 +1845,14 @@ def is_not_distinct_from(a: Any, b: Any) -> Any:
 
 
 # deprecated 1.4; see #5435
-isnot_distinct_from = is_not_distinct_from
+if TYPE_CHECKING:
+
+    @_operator_fn
+    def isnot_distinct_from(a: Any, b: Any) -> Any:
+        ...
+
+else:
+    isnot_distinct_from = is_not_distinct_from
 
 
 @comparison_op
@@ -1800,7 +1868,14 @@ def is_not(a: Any, b: Any) -> Any:
 
 
 # 1.4 deprecated; see #5429
-isnot = is_not
+if TYPE_CHECKING:
+
+    @_operator_fn
+    def isnot(a: Any, b: Any) -> Any:
+        ...
+
+else:
+    isnot = is_not
 
 
 @_operator_fn
@@ -1826,7 +1901,14 @@ def not_like_op(a: Any, b: Any, escape: Optional[str] = None) -> Any:
 
 
 # 1.4 deprecated; see #5435
-notlike_op = not_like_op
+if TYPE_CHECKING:
+
+    @_operator_fn
+    def notlike_op(a: Any, b: Any, escape: Optional[str] = None) -> Any:
+        ...
+
+else:
+    notlike_op = not_like_op
 
 
 @comparison_op
@@ -1842,7 +1924,14 @@ def not_ilike_op(a: Any, b: Any, escape: Optional[str] = None) -> Any:
 
 
 # 1.4 deprecated; see #5435
-notilike_op = not_ilike_op
+if TYPE_CHECKING:
+
+    @_operator_fn
+    def notilike_op(a: Any, b: Any, escape: Optional[str] = None) -> Any:
+        ...
+
+else:
+    notilike_op = not_ilike_op
 
 
 @comparison_op
@@ -1858,7 +1947,14 @@ def not_between_op(a: Any, b: Any, c: Any, symmetric: bool = False) -> Any:
 
 
 # 1.4 deprecated; see #5435
-notbetween_op = not_between_op
+if TYPE_CHECKING:
+
+    @_operator_fn
+    def notbetween_op(a: Any, b: Any, c: Any, symmetric: bool = False) -> Any:
+        ...
+
+else:
+    notbetween_op = not_between_op
 
 
 @comparison_op
@@ -1874,7 +1970,14 @@ def not_in_op(a: Any, b: Any) -> Any:
 
 
 # 1.4 deprecated; see #5429
-notin_op = not_in_op
+if TYPE_CHECKING:
+
+    @_operator_fn
+    def notin_op(a: Any, b: Any) -> Any:
+        ...
+
+else:
+    notin_op = not_in_op
 
 
 @_operator_fn
@@ -1931,7 +2034,16 @@ def not_startswith_op(
 
 
 # 1.4 deprecated; see #5435
-notstartswith_op = not_startswith_op
+if TYPE_CHECKING:
+
+    @_operator_fn
+    def notstartswith_op(
+        a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False
+    ) -> Any:
+        ...
+
+else:
+    notstartswith_op = not_startswith_op
 
 
 @comparison_op
@@ -1967,7 +2079,16 @@ def not_endswith_op(
 
 
 # 1.4 deprecated; see #5435
-notendswith_op = not_endswith_op
+if TYPE_CHECKING:
+
+    @_operator_fn
+    def notendswith_op(
+        a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False
+    ) -> Any:
+        ...
+
+else:
+    notendswith_op = not_endswith_op
 
 
 @comparison_op
@@ -2003,7 +2124,16 @@ def not_contains_op(
 
 
 # 1.4 deprecated; see #5435
-notcontains_op = not_contains_op
+if TYPE_CHECKING:
+
+    @_operator_fn
+    def notcontains_op(
+        a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False
+    ) -> Any:
+        ...
+
+else:
+    notcontains_op = not_contains_op
 
 
 @comparison_op
@@ -2054,7 +2184,14 @@ def not_match_op(a: Any, b: Any, **kw: Any) -> Any:
 
 
 # 1.4 deprecated; see #5429
-notmatch_op = not_match_op
+if TYPE_CHECKING:
+
+    @_operator_fn
+    def notmatch_op(a: Any, b: Any, **kw: Any) -> Any:
+        ...
+
+else:
+    notmatch_op = not_match_op
 
 
 @_operator_fn
@@ -2093,7 +2230,14 @@ def nulls_first_op(a: Any) -> Any:
 
 
 # 1.4 deprecated; see #5435
-nullsfirst_op = nulls_first_op
+if TYPE_CHECKING:
+
+    @_operator_fn
+    def nullsfirst_op(a: Any) -> Any:
+        ...
+
+else:
+    nullsfirst_op = nulls_first_op
 
 
 @_operator_fn
@@ -2102,7 +2246,14 @@ def nulls_last_op(a: Any) -> Any:
 
 
 # 1.4 deprecated; see #5435
-nullslast_op = nulls_last_op
+if TYPE_CHECKING:
+
+    @_operator_fn
+    def nullslast_op(a: Any) -> Any:
+        ...
+
+else:
+    nullslast_op = nulls_last_op
 
 
 @_operator_fn
index 33db5f2ccf173036a08609bfc6c3b0d253939b6b..c55442be998d2738dc2808438c1d53d8f65258f2 100644 (file)
@@ -64,6 +64,17 @@ stmt = select(column("q")).where(lambda: column("g") > 5).where(c2 == 5)
 
 expr9 = c1.bool_op("@@")(func.to_tsquery("some & query"))
 
+# add tests for #9148
+and_(c1.is_(q))
+and_(c1.is_not(q))
+and_(c1.isnot(q))
+and_(c1.not_in(["x"]))
+and_(c1.notin_(["x"]))
+and_(c1.not_like("x"))
+and_(c1.notlike("x"))
+and_(c1.not_ilike("x"))
+and_(c1.notilike("x"))
+
 
 if typing.TYPE_CHECKING: