]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
update typing for mypy 1.11; pin plugin to <1.11
authorFederico Caselli <cfederico87@gmail.com>
Mon, 22 Jul 2024 21:17:45 +0000 (23:17 +0200)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 27 Jul 2024 16:21:34 +0000 (12:21 -0400)
Fixed internal typing issues to establish compatibility with mypy 1.11.0.
Note that this does not include issues which have arisen with the
deprecated mypy plugin used by SQLAlchemy 1.4-style code; see the addiional
change note for this plugin indicating revised compatibility.

The legacy mypy plugin is no longer fully functional with the latest series
of mypy 1.11.0, as changes in the mypy interpreter are no longer compatible
with the approach used by the plugin.  If code is dependent on the legacy
mypy plugin with sqlalchemy2-stubs, it's recommended to pin mypy to be
below the 1.11.0 series.    Seek upgrading to the 2.0 series of SQLAlchemy
and migrating to the modern type annotations.

Change-Id: Ib8fef93ede588430dc0f7ed44ef887649a415821
(cherry picked from commit 156fef61135a55c6ad17765b64155801f1dbea66)

19 files changed:
doc/build/changelog/unreleased_14/mypy1110.rst [new file with mode: 0644]
doc/build/changelog/unreleased_20/mypy1110.rst [new file with mode: 0644]
doc/build/orm/extensions/mypy.rst
lib/sqlalchemy/engine/interfaces.py
lib/sqlalchemy/ext/mypy/util.py
lib/sqlalchemy/orm/descriptor_props.py
lib/sqlalchemy/orm/mapped_collection.py
lib/sqlalchemy/orm/query.py
lib/sqlalchemy/orm/util.py
lib/sqlalchemy/sql/base.py
lib/sqlalchemy/sql/coercions.py
lib/sqlalchemy/sql/compiler.py
lib/sqlalchemy/sql/crud.py
lib/sqlalchemy/sql/elements.py
lib/sqlalchemy/sql/sqltypes.py
lib/sqlalchemy/util/compat.py
lib/sqlalchemy/util/langhelpers.py
test/ext/mypy/test_mypy_plugin_py3k.py
tox.ini

diff --git a/doc/build/changelog/unreleased_14/mypy1110.rst b/doc/build/changelog/unreleased_14/mypy1110.rst
new file mode 100644 (file)
index 0000000..1dc5e0d
--- /dev/null
@@ -0,0 +1,14 @@
+.. change::
+    :tags: bug, mypy
+    :versions: 2.0
+
+    The deprecated mypy plugin is no longer fully functional with the latest
+    series of mypy 1.11.0, as changes in the mypy interpreter are no longer
+    compatible with the approach used by the plugin.  If code is dependent on
+    the mypy plugin with sqlalchemy2-stubs, it's recommended to pin mypy to be
+    below the 1.11.0 series.    Seek upgrading to the 2.0 series of SQLAlchemy
+    and migrating to the modern type annotations.
+
+    .. seealso::
+
+        :ref:`mypy_toplevel`
diff --git a/doc/build/changelog/unreleased_20/mypy1110.rst b/doc/build/changelog/unreleased_20/mypy1110.rst
new file mode 100644 (file)
index 0000000..f722c40
--- /dev/null
@@ -0,0 +1,7 @@
+.. change::
+    :tags: bug, mypy
+
+    Fixed internal typing issues to establish compatibility with mypy 1.11.0.
+    Note that this does not include issues which have arisen with the
+    deprecated mypy plugin used by SQLAlchemy 1.4-style code; see the addiional
+    change note for this plugin indicating revised compatibility.
index afd34929af628803972fba21aa8b83c362f323b7..dbca3f35f91bf9ec8dba7c6c19ff8ba1c596bd13 100644 (file)
@@ -13,7 +13,8 @@ the :func:`_orm.mapped_column` construct introduced in SQLAlchemy 2.0.
 
     **The SQLAlchemy Mypy Plugin is DEPRECATED, and will be removed possibly
     as early as the SQLAlchemy 2.1 release.  We would urge users to please
-    migrate away from it ASAP.**
+    migrate away from it ASAP.   The mypy plugin also works only up until
+    mypy version 1.10.1.    version 1.11.0 and greater may not work properly.**
 
     This plugin cannot be maintained across constantly changing releases
     of mypy and its stability going forward CANNOT be guaranteed.
@@ -24,7 +25,11 @@ the :func:`_orm.mapped_column` construct introduced in SQLAlchemy 2.0.
 
 .. topic:: SQLAlchemy Mypy Plugin Status Update
 
-   **Updated July 2023**
+   **Updated July 2024**
+
+   The mypy plugin is supported **only up until mypy 1.10.1, and it will have
+   issues running with 1.11.0 or greater**.   Use with mypy 1.11.0 or greater
+   may have error conditions which currently cannot be resolved.
 
    For SQLAlchemy 2.0, the Mypy plugin continues to work at the level at which
    it reached in the SQLAlchemy 1.4 release.  SQLAlchemy 2.0 however features
index 7a152c3305c2b512d0a6c7251210bacf8bb629f4..17a133f27a954b3839a3cdd099c87ae3a457ebb5 100644 (file)
@@ -1253,8 +1253,7 @@ class Dialect(EventTarget):
         """
         raise NotImplementedError()
 
-    @classmethod
-    def type_descriptor(cls, typeobj: TypeEngine[_T]) -> TypeEngine[_T]:
+    def type_descriptor(self, typeobj: TypeEngine[_T]) -> TypeEngine[_T]:
         """Transform a generic type to a dialect-specific type.
 
         Dialect classes will usually use the
@@ -1316,6 +1315,7 @@ class Dialect(EventTarget):
     def get_multi_columns(
         self,
         connection: Connection,
+        *,
         schema: Optional[str] = None,
         filter_names: Optional[Collection[str]] = None,
         **kw: Any,
@@ -1364,6 +1364,7 @@ class Dialect(EventTarget):
     def get_multi_pk_constraint(
         self,
         connection: Connection,
+        *,
         schema: Optional[str] = None,
         filter_names: Optional[Collection[str]] = None,
         **kw: Any,
@@ -1410,6 +1411,7 @@ class Dialect(EventTarget):
     def get_multi_foreign_keys(
         self,
         connection: Connection,
+        *,
         schema: Optional[str] = None,
         filter_names: Optional[Collection[str]] = None,
         **kw: Any,
@@ -1569,6 +1571,7 @@ class Dialect(EventTarget):
     def get_multi_indexes(
         self,
         connection: Connection,
+        *,
         schema: Optional[str] = None,
         filter_names: Optional[Collection[str]] = None,
         **kw: Any,
@@ -1615,6 +1618,7 @@ class Dialect(EventTarget):
     def get_multi_unique_constraints(
         self,
         connection: Connection,
+        *,
         schema: Optional[str] = None,
         filter_names: Optional[Collection[str]] = None,
         **kw: Any,
@@ -1662,6 +1666,7 @@ class Dialect(EventTarget):
     def get_multi_check_constraints(
         self,
         connection: Connection,
+        *,
         schema: Optional[str] = None,
         filter_names: Optional[Collection[str]] = None,
         **kw: Any,
@@ -1704,6 +1709,7 @@ class Dialect(EventTarget):
     def get_multi_table_options(
         self,
         connection: Connection,
+        *,
         schema: Optional[str] = None,
         filter_names: Optional[Collection[str]] = None,
         **kw: Any,
@@ -1755,6 +1761,7 @@ class Dialect(EventTarget):
     def get_multi_table_comment(
         self,
         connection: Connection,
+        *,
         schema: Optional[str] = None,
         filter_names: Optional[Collection[str]] = None,
         **kw: Any,
index 7f04c481d3474f271e86363e47fb6711a22e6e62..af0882bc3075006f1f9fdf9964a938b3ec4fde8e 100644 (file)
@@ -80,7 +80,7 @@ class SQLAlchemyAttribute:
             "name": self.name,
             "line": self.line,
             "column": self.column,
-            "type": self.type.serialize(),
+            "type": serialize_type(self.type),
         }
 
     def expand_typevar_from_subtype(self, sub_type: TypeInfo) -> None:
@@ -336,3 +336,22 @@ def info_for_cls(
         return sym.node
 
     return cls.info
+
+
+def serialize_type(typ: Type) -> Union[str, JsonDict]:
+    try:
+        return typ.serialize()
+    except Exception:
+        pass
+    if hasattr(typ, "args"):
+        typ.args = tuple(
+            (
+                a.resolve_string_annotation()
+                if hasattr(a, "resolve_string_annotation")
+                else a
+            )
+            for a in typ.args
+        )
+    elif hasattr(typ, "resolve_string_annotation"):
+        typ = typ.resolve_string_annotation()
+    return typ.serialize()
index a3650f5f001fcdf5ab7032ebacfee8d1f68ee769..faf287cce6c2aeccc3f4fffb67e673ecf12d5758 100644 (file)
@@ -781,7 +781,9 @@ class CompositeProperty(
             elif isinstance(self.prop.composite_class, type) and isinstance(
                 value, self.prop.composite_class
             ):
-                values = self.prop._composite_values_from_instance(value)
+                values = self.prop._composite_values_from_instance(
+                    value  # type: ignore[arg-type]
+                )
             else:
                 raise sa_exc.ArgumentError(
                     "Can't UPDATE composite attribute %s to %r"
index 13c6b689e1d2e6026af9d1540d1fccb9ae537deb..0d3079fb5ab9d0b8f25ee41b75e475a9b1e451c1 100644 (file)
@@ -29,6 +29,8 @@ from .. import util
 from ..sql import coercions
 from ..sql import expression
 from ..sql import roles
+from ..util.langhelpers import Missing
+from ..util.langhelpers import MissingOr
 from ..util.typing import Literal
 
 if TYPE_CHECKING:
@@ -40,8 +42,6 @@ if TYPE_CHECKING:
 _KT = TypeVar("_KT", bound=Any)
 _VT = TypeVar("_VT", bound=Any)
 
-_F = TypeVar("_F", bound=Callable[[Any], Any])
-
 
 class _PlainColumnGetter(Generic[_KT]):
     """Plain column getter, stores collection of Column objects
@@ -70,7 +70,7 @@ class _PlainColumnGetter(Generic[_KT]):
     def _cols(self, mapper: Mapper[_KT]) -> Sequence[ColumnElement[_KT]]:
         return self.cols
 
-    def __call__(self, value: _KT) -> Union[_KT, Tuple[_KT, ...]]:
+    def __call__(self, value: _KT) -> MissingOr[Union[_KT, Tuple[_KT, ...]]]:
         state = base.instance_state(value)
         m = base._state_mapper(state)
 
@@ -83,7 +83,7 @@ class _PlainColumnGetter(Generic[_KT]):
         else:
             obj = key[0]
             if obj is None:
-                return _UNMAPPED_AMBIGUOUS_NONE
+                return Missing
             else:
                 return obj
 
@@ -198,9 +198,6 @@ def column_keyed_dict(
     )
 
 
-_UNMAPPED_AMBIGUOUS_NONE = object()
-
-
 class _AttrGetter:
     __slots__ = ("attr_name", "getter")
 
@@ -217,9 +214,9 @@ class _AttrGetter:
                 dict_ = state.dict
                 obj = dict_.get(self.attr_name, base.NO_VALUE)
                 if obj is None:
-                    return _UNMAPPED_AMBIGUOUS_NONE
+                    return Missing
             else:
-                return _UNMAPPED_AMBIGUOUS_NONE
+                return Missing
 
         return obj
 
@@ -277,7 +274,7 @@ def attribute_keyed_dict(
 
 
 def keyfunc_mapping(
-    keyfunc: _F,
+    keyfunc: Callable[[Any], Any],
     *,
     ignore_unpopulated_attribute: bool = False,
 ) -> Type[KeyFuncDict[_KT, Any]]:
@@ -353,7 +350,7 @@ class KeyFuncDict(Dict[_KT, _VT]):
 
     def __init__(
         self,
-        keyfunc: _F,
+        keyfunc: Callable[[Any], Any],
         *dict_args: Any,
         ignore_unpopulated_attribute: bool = False,
     ) -> None:
@@ -377,7 +374,7 @@ class KeyFuncDict(Dict[_KT, _VT]):
     @classmethod
     def _unreduce(
         cls,
-        keyfunc: _F,
+        keyfunc: Callable[[Any], Any],
         values: Dict[_KT, _KT],
         adapter: Optional[CollectionAdapter] = None,
     ) -> "KeyFuncDict[_KT, _KT]":
@@ -464,7 +461,7 @@ class KeyFuncDict(Dict[_KT, _VT]):
                 )
             else:
                 return
-        elif key is _UNMAPPED_AMBIGUOUS_NONE:
+        elif key is Missing:
             if not self.ignore_unpopulated_attribute:
                 self._raise_for_unpopulated(
                     value, _sa_initiator, warn_only=True
@@ -492,7 +489,7 @@ class KeyFuncDict(Dict[_KT, _VT]):
                     value, _sa_initiator, warn_only=False
                 )
             return
-        elif key is _UNMAPPED_AMBIGUOUS_NONE:
+        elif key is Missing:
             if not self.ignore_unpopulated_attribute:
                 self._raise_for_unpopulated(
                     value, _sa_initiator, warn_only=True
@@ -514,7 +511,7 @@ class KeyFuncDict(Dict[_KT, _VT]):
 
 
 def _mapped_collection_cls(
-    keyfunc: _F, ignore_unpopulated_attribute: bool
+    keyfunc: Callable[[Any], Any], ignore_unpopulated_attribute: bool
 ) -> Type[KeyFuncDict[_KT, _KT]]:
     class _MKeyfuncMapped(KeyFuncDict[_KT, _KT]):
         def __init__(self, *dict_args: Any) -> None:
index 1dfc9cb3459d0d180bd745291aefc5cf0e7bb86b..4f0b4891fd69ca4c1856325966422c51db847933 100644 (file)
@@ -731,7 +731,7 @@ class Query(
         )
 
     @overload
-    def as_scalar(
+    def as_scalar(  # type: ignore[overload-overlap]
         self: Query[Tuple[_MAYBE_ENTITY]],
     ) -> ScalarSelect[_MAYBE_ENTITY]: ...
 
index 9835f824470247ba6b906d6fe4119275b1455f54..0b4ad88ed8b92e7f076bf9b176b651b58baea4cb 100644 (file)
@@ -1681,7 +1681,7 @@ class Bundle(
     c: ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]
     """An alias for :attr:`.Bundle.columns`."""
 
-    def _clone(self):
+    def _clone(self, **kw):
         cloned = self.__class__.__new__(self.__class__)
         cloned.__dict__.update(self.__dict__)
         return cloned
index 8ad17e2c1a4f0f9e4b481cccf4f151c2bf1c112d..e4a7256b5d8780af5a9595adb71597a9080999d2 100644 (file)
@@ -2137,7 +2137,7 @@ class ColumnSet(util.OrderedSet["ColumnClause[Any]"]):
                     l.append(c == local)
         return elements.and_(*l)
 
-    def __hash__(self):
+    def __hash__(self):  # type: ignore[override]
         return hash(tuple(x for x in self))
 
 
index 22d6091552233bf6e2a077f8783f676997008e2b..0c998c667f22483b35d4187a920b50f035ecb7bc 100644 (file)
@@ -493,6 +493,7 @@ class RoleImpl:
         element: Any,
         argname: Optional[str] = None,
         resolved: Optional[Any] = None,
+        *,
         advice: Optional[str] = None,
         code: Optional[str] = None,
         err: Optional[Exception] = None,
@@ -595,7 +596,7 @@ def _no_text_coercion(
 class _NoTextCoercion(RoleImpl):
     __slots__ = ()
 
-    def _literal_coercion(self, element, argname=None, **kw):
+    def _literal_coercion(self, element, *, argname=None, **kw):
         if isinstance(element, str) and issubclass(
             elements.TextClause, self._role_class
         ):
@@ -613,7 +614,7 @@ class _CoerceLiterals(RoleImpl):
     def _text_coercion(self, element, argname=None):
         return _no_text_coercion(element, argname)
 
-    def _literal_coercion(self, element, argname=None, **kw):
+    def _literal_coercion(self, element, *, argname=None, **kw):
         if isinstance(element, str):
             if self._coerce_star and element == "*":
                 return elements.ColumnClause("*", is_literal=True)
@@ -641,7 +642,8 @@ class LiteralValueImpl(RoleImpl):
         self,
         element,
         resolved,
-        argname,
+        argname=None,
+        *,
         type_=None,
         literal_execute=False,
         **kw,
@@ -659,7 +661,7 @@ class LiteralValueImpl(RoleImpl):
             literal_execute=literal_execute,
         )
 
-    def _literal_coercion(self, element, argname=None, type_=None, **kw):
+    def _literal_coercion(self, element, **kw):
         return element
 
 
@@ -671,6 +673,7 @@ class _SelectIsNotFrom(RoleImpl):
         element: Any,
         argname: Optional[str] = None,
         resolved: Optional[Any] = None,
+        *,
         advice: Optional[str] = None,
         code: Optional[str] = None,
         err: Optional[Exception] = None,
@@ -745,7 +748,7 @@ class ExpressionElementImpl(_ColumnCoercions, RoleImpl):
     __slots__ = ()
 
     def _literal_coercion(
-        self, element, name=None, type_=None, argname=None, is_crud=False, **kw
+        self, element, *, name=None, type_=None, is_crud=False, **kw
     ):
         if (
             element is None
@@ -787,15 +790,22 @@ class ExpressionElementImpl(_ColumnCoercions, RoleImpl):
 class BinaryElementImpl(ExpressionElementImpl, RoleImpl):
     __slots__ = ()
 
-    def _literal_coercion(
-        self, element, expr, operator, bindparam_type=None, argname=None, **kw
+    def _literal_coercion(  # type: ignore[override]
+        self,
+        element,
+        *,
+        expr,
+        operator,
+        bindparam_type=None,
+        argname=None,
+        **kw,
     ):
         try:
             return expr._bind_param(operator, element, type_=bindparam_type)
         except exc.ArgumentError as err:
             self._raise_for_expected(element, err=err)
 
-    def _post_coercion(self, resolved, expr, bindparam_type=None, **kw):
+    def _post_coercion(self, resolved, *, expr, bindparam_type=None, **kw):
         if resolved.type._isnull and not expr.type._isnull:
             resolved = resolved._with_binary_element_type(
                 bindparam_type if bindparam_type is not None else expr.type
@@ -833,7 +843,9 @@ class InElementImpl(RoleImpl):
             % (elem.__class__.__name__)
         )
 
-    def _literal_coercion(self, element, expr, operator, **kw):
+    def _literal_coercion(  # type: ignore[override]
+        self, element, *, expr, operator, **kw
+    ):
         if util.is_non_string_iterable(element):
             non_literal_expressions: Dict[
                 Optional[operators.ColumnOperators],
@@ -867,7 +879,7 @@ class InElementImpl(RoleImpl):
         else:
             self._raise_for_expected(element, **kw)
 
-    def _post_coercion(self, element, expr, operator, **kw):
+    def _post_coercion(self, element, *, expr, operator, **kw):
         if element._is_select_base:
             # for IN, we are doing scalar_subquery() coercion without
             # a warning
@@ -893,12 +905,10 @@ class OnClauseImpl(_ColumnCoercions, RoleImpl):
 
     _coerce_consts = True
 
-    def _literal_coercion(
-        self, element, name=None, type_=None, argname=None, is_crud=False, **kw
-    ):
+    def _literal_coercion(self, element, **kw):
         self._raise_for_expected(element)
 
-    def _post_coercion(self, resolved, original_element=None, **kw):
+    def _post_coercion(self, resolved, *, original_element=None, **kw):
         # this is a hack right now as we want to use coercion on an
         # ORM InstrumentedAttribute, but we want to return the object
         # itself if it is one, not its clause element.
@@ -983,7 +993,7 @@ class GroupByImpl(ByOfImpl, RoleImpl):
 class DMLColumnImpl(_ReturnsStringKey, RoleImpl):
     __slots__ = ()
 
-    def _post_coercion(self, element, as_key=False, **kw):
+    def _post_coercion(self, element, *, as_key=False, **kw):
         if as_key:
             return element.key
         else:
@@ -993,7 +1003,7 @@ class DMLColumnImpl(_ReturnsStringKey, RoleImpl):
 class ConstExprImpl(RoleImpl):
     __slots__ = ()
 
-    def _literal_coercion(self, element, argname=None, **kw):
+    def _literal_coercion(self, element, *, argname=None, **kw):
         if element is None:
             return elements.Null()
         elif element is False:
@@ -1019,7 +1029,7 @@ class TruncatedLabelImpl(_StringOnly, RoleImpl):
         else:
             self._raise_for_expected(element, argname, resolved)
 
-    def _literal_coercion(self, element, argname=None, **kw):
+    def _literal_coercion(self, element, **kw):
         """coerce the given value to :class:`._truncated_label`.
 
         Existing :class:`._truncated_label` and
@@ -1069,7 +1079,9 @@ class LimitOffsetImpl(RoleImpl):
         else:
             self._raise_for_expected(element, argname, resolved)
 
-    def _literal_coercion(self, element, name, type_, **kw):
+    def _literal_coercion(  # type: ignore[override]
+        self, element, *, name, type_, **kw
+    ):
         if element is None:
             return None
         else:
@@ -1111,7 +1123,7 @@ 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
+        self, element, argname=None, resolved=None, *, advice=None, **kw
     ):
         if not advice and isinstance(element, list):
             advice = (
@@ -1149,7 +1161,9 @@ class ReturnsRowsImpl(RoleImpl):
 class StatementImpl(_CoerceLiterals, RoleImpl):
     __slots__ = ()
 
-    def _post_coercion(self, resolved, original_element, argname=None, **kw):
+    def _post_coercion(
+        self, resolved, *, original_element, argname=None, **kw
+    ):
         if resolved is not original_element and not isinstance(
             original_element, str
         ):
@@ -1215,7 +1229,7 @@ class JoinTargetImpl(RoleImpl):
 
     _skip_clauseelement_for_target_match = True
 
-    def _literal_coercion(self, element, argname=None, **kw):
+    def _literal_coercion(self, element, *, argname=None, **kw):
         self._raise_for_expected(element, argname)
 
     def _implicit_coercions(
@@ -1223,6 +1237,7 @@ class JoinTargetImpl(RoleImpl):
         element: Any,
         resolved: Any,
         argname: Optional[str] = None,
+        *,
         legacy: bool = False,
         **kw: Any,
     ) -> Any:
@@ -1256,6 +1271,7 @@ class FromClauseImpl(_SelectIsNotFrom, _NoTextCoercion, RoleImpl):
         element: Any,
         resolved: Any,
         argname: Optional[str] = None,
+        *,
         explicit_subquery: bool = False,
         allow_select: bool = True,
         **kw: Any,
@@ -1277,7 +1293,7 @@ class FromClauseImpl(_SelectIsNotFrom, _NoTextCoercion, RoleImpl):
         else:
             self._raise_for_expected(element, argname, resolved)
 
-    def _post_coercion(self, element, deannotate=False, **kw):
+    def _post_coercion(self, element, *, deannotate=False, **kw):
         if deannotate:
             return element._deannotate()
         else:
@@ -1292,7 +1308,7 @@ class StrictFromClauseImpl(FromClauseImpl):
         element: Any,
         resolved: Any,
         argname: Optional[str] = None,
-        explicit_subquery: bool = False,
+        *,
         allow_select: bool = False,
         **kw: Any,
     ) -> Any:
@@ -1312,7 +1328,7 @@ class StrictFromClauseImpl(FromClauseImpl):
 class AnonymizedFromClauseImpl(StrictFromClauseImpl):
     __slots__ = ()
 
-    def _post_coercion(self, element, flat=False, name=None, **kw):
+    def _post_coercion(self, element, *, flat=False, name=None, **kw):
         assert name is None
 
         return element._anonymous_fromclause(flat=flat)
index 6d6d8278af6c7d81b4f39d913ac8c55939b1582a..634e5ce118ddb55da4cbe4efb95f2a9f7a05832a 100644 (file)
@@ -6489,8 +6489,10 @@ class StrSQLCompiler(SQLCompiler):
     def visit_json_path_getitem_op_binary(self, binary, operator, **kw):
         return self.visit_getitem_binary(binary, operator, **kw)
 
-    def visit_sequence(self, seq, **kw):
-        return "<next sequence value: %s>" % self.preparer.format_sequence(seq)
+    def visit_sequence(self, sequence, **kw):
+        return (
+            f"<next sequence value: {self.preparer.format_sequence(sequence)}>"
+        )
 
     def returning_clause(
         self,
@@ -6524,7 +6526,7 @@ class StrSQLCompiler(SQLCompiler):
             for t in extra_froms
         )
 
-    def visit_empty_set_expr(self, type_, **kw):
+    def visit_empty_set_expr(self, element_types, **kw):
         return "SELECT 1 WHERE 1!=1"
 
     def get_from_hint_text(self, table, text):
index 499a19d97cc2f81b5196d0bd7a2482b54ec35f1d..d142665823928ede47e113e862e050f3bdb657e9 100644 (file)
@@ -1286,7 +1286,7 @@ class _multiparam_column(elements.ColumnElement[Any]):
     def compare(self, other, **kw):
         raise NotImplementedError()
 
-    def _copy_internals(self, other, **kw):
+    def _copy_internals(self, **kw):
         raise NotImplementedError()
 
     def __eq__(self, other):
index 048a9ea6228d25477373167bac86da4cf3aa2495..70c9e01da5745512e4b583ee1b5c9d508ebc480b 100644 (file)
@@ -3999,7 +3999,7 @@ class Slice(ColumnElement[Any]):
         self.type = type_api.NULLTYPE
 
     def self_group(self, against: Optional[OperatorType] = None) -> Self:
-        assert against is operator.getitem  # type: ignore[comparison-overlap]
+        assert against is operator.getitem
         return self
 
 
index c20df07a6b80beb0ba2232efba95786d38daf5a8..f29131c933cac9e73165d019aaf006a800118cdd 100644 (file)
@@ -1011,7 +1011,7 @@ class SchemaType(SchemaEventTarget, TypeEngineMixin):
         if _adapted_from:
             self.dispatch = self.dispatch._join(_adapted_from.dispatch)
 
-    def _set_parent(self, column, **kw):
+    def _set_parent(self, parent, **kw):
         # set parent hook is when this type is associated with a column.
         # Column calls it for all SchemaEventTarget instances, either the
         # base type and/or variants in _variant_mapping.
@@ -1025,7 +1025,7 @@ class SchemaType(SchemaEventTarget, TypeEngineMixin):
         # on_table/metadata_create/drop in this method, which is used by
         # "native" types with a separate CREATE/DROP e.g. Postgresql.ENUM
 
-        column._on_table_attach(util.portable_instancemethod(self._set_table))
+        parent._on_table_attach(util.portable_instancemethod(self._set_table))
 
     def _variant_mapping_for_set_table(self, column):
         if column.type._variant_mapping:
@@ -1669,10 +1669,10 @@ class Enum(String, SchemaType, Emulated, TypeEngine[Union[str, enum.Enum]]):
         assert "_enums" in kw
         return impltype(**kw)
 
-    def adapt(self, impltype, **kw):
+    def adapt(self, cls, **kw):
         kw["_enums"] = self._enums_argument
         kw["_disable_warnings"] = True
-        return super().adapt(impltype, **kw)
+        return super().adapt(cls, **kw)
 
     def _should_create_constraint(self, compiler, **kw):
         if not self._is_impl_for_variant(compiler.dialect, kw):
@@ -3065,13 +3065,13 @@ class ARRAY(
     def compare_values(self, x, y):
         return x == y
 
-    def _set_parent(self, column, outer=False, **kw):
+    def _set_parent(self, parent, outer=False, **kw):
         """Support SchemaEventTarget"""
 
         if not outer and isinstance(self.item_type, SchemaEventTarget):
-            self.item_type._set_parent(column, **kw)
+            self.item_type._set_parent(parent, **kw)
 
-    def _set_parent_with_dispatch(self, parent):
+    def _set_parent_with_dispatch(self, parent, **kw):
         """Support SchemaEventTarget"""
 
         super()._set_parent_with_dispatch(parent, outer=True)
index e1b5e661433fa730df584a2469494706294b78c6..fea881e730ad54f8e17e6594d8228dc275cd83d5 100644 (file)
@@ -58,7 +58,7 @@ class FullArgSpec(typing.NamedTuple):
     varkw: Optional[str]
     defaults: Optional[Tuple[Any, ...]]
     kwonlyargs: List[str]
-    kwonlydefaults: Dict[str, Any]
+    kwonlydefaults: Optional[Dict[str, Any]]
     annotations: Dict[str, Any]
 
 
index 72cb28d1122d5504198c7d24599ba5ed3b7d7a33..9312976e71f1985d487d46a9f2b16977b4d05977 100644 (file)
@@ -2208,3 +2208,11 @@ def has_compiled_ext(raise_=False):
         )
     else:
         return False
+
+
+class _Missing(enum.Enum):
+    Missing = enum.auto()
+
+
+Missing = _Missing.Missing
+MissingOr = Union[_T, Literal[_Missing.Missing]]
index f1b36ac52bb836393ec0d78d800651a63970bfb9..e1aa1f9655120706e8d5b4871d2fb530dca7b68f 100644 (file)
@@ -1,4 +1,5 @@
 import os
+import pathlib
 import shutil
 
 from sqlalchemy import testing
@@ -25,8 +26,12 @@ def _incremental_dirs():
 
 class MypyPluginTest(fixtures.MypyTest):
     @testing.combinations(
-        *[(pathname) for pathname in _incremental_dirs()],
+        *[
+            (pathlib.Path(pathname).name, pathname)
+            for pathname in _incremental_dirs()
+        ],
         argnames="pathname",
+        id_="ia",
     )
     @testing.requires.patch_library
     def test_incremental(self, mypy_runner, per_func_cachedir, pathname):
diff --git a/tox.ini b/tox.ini
index e80fe4ccec0d307a1a21616e0080f6d4ba29282e..93b86dd5f75221b69aa490e5062d42f54655b799 100644 (file)
--- a/tox.ini
+++ b/tox.ini
@@ -192,7 +192,8 @@ commands=
 deps=
      greenlet != 0.4.17
      importlib_metadata; python_version < '3.8'
-     mypy >= 1.6.0,<1.11.0   # temporary, REMOVE upper bound
+     mypy >= 1.6.0
+     types-greenlet
 commands =
     mypy  {env:MYPY_COLOR} ./lib/sqlalchemy
     # pyright changes too often with not-exactly-correct errors