diff --git a/mypy/messages.py b/mypy/messages.py index f626d4c71916..571cebb1b174 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -2432,13 +2432,13 @@ def format_long_tuple_type(self, typ: TupleType) -> str: """Format very long tuple type using an ellipsis notation""" item_cnt = len(typ.items) if item_cnt > MAX_TUPLE_ITEMS: - return "tuple[{}, {}, ... <{} more items>]".format( + return '"tuple[{}, {}, ... <{} more items>]"'.format( format_type_bare(typ.items[0], self.options), format_type_bare(typ.items[1], self.options), str(item_cnt - 2), ) else: - return format_type_bare(typ, self.options) + return format_type(typ, self.options) def generate_incompatible_tuple_error( self, @@ -2517,15 +2517,12 @@ def iteration_dependent_errors(self, iter_errors: IterationDependentErrors) -> N def quote_type_string(type_string: str) -> str: """Quotes a type representation for use in messages.""" - no_quote_regex = r"^<(tuple|union): \d+ items>$" if ( type_string in ["Module", "overloaded function", ""] or type_string.startswith("Module ") - or re.match(no_quote_regex, type_string) is not None or type_string.endswith("?") ): - # Messages are easier to read if these aren't quoted. We use a - # regex to match strings with variable contents. + # These messages are easier to read if these aren't quoted. return type_string return f'"{type_string}"' diff --git a/mypy/types.py b/mypy/types.py index a73ac3c3524a..d7dd3e1f2dce 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -5,18 +5,7 @@ import sys from abc import abstractmethod from collections.abc import Iterable, Sequence -from typing import ( - TYPE_CHECKING, - Any, - ClassVar, - Final, - NamedTuple, - NewType, - TypeVar, - Union, - cast, - overload, -) +from typing import TYPE_CHECKING, Any, ClassVar, Final, NewType, TypeVar, Union, cast, overload from typing_extensions import Self, TypeAlias as _TypeAlias, TypeGuard import mypy.nodes @@ -1607,11 +1596,25 @@ def bound(self) -> bool: return bool(self.items) and self.items[0].is_bound -class FormalArgument(NamedTuple): - name: str | None - pos: int | None - typ: Type - required: bool +class FormalArgument: + def __init__(self, name: str | None, pos: int | None, typ: Type, required: bool) -> None: + self.name = name + self.pos = pos + self.typ = typ + self.required = required + + def __eq__(self, other: object) -> bool: + if not isinstance(other, FormalArgument): + return NotImplemented + return ( + self.name == other.name + and self.pos == other.pos + and self.typ == other.typ + and self.required == other.required + ) + + def __hash__(self) -> int: + return hash((self.name, self.pos, self.typ, self.required)) class Parameters(ProperType): diff --git a/test-data/unit/check-tuples.test b/test-data/unit/check-tuples.test index 615ba129dad5..cfdd2aacc4d2 100644 --- a/test-data/unit/check-tuples.test +++ b/test-data/unit/check-tuples.test @@ -1612,7 +1612,7 @@ t4: Tuple[int, int, int, int, int, int, int, int, int, int, int, int] = (1, 2, 3 t5: Tuple[int, int] = (1, 2, "s", 4) # E: Incompatible types in assignment (expression has type "tuple[int, int, str, int]", variable has type "tuple[int, int]") # long initializer assignment with mismatched pairs -t6: Tuple[int, int, int, int, int, int, int, int, int, int, int, int] = (1, 2, 3, 4, 5, 6, 7, 8, "str", "str", "str", "str", 1, 1, 1, 1, 1) # E: Incompatible types in assignment (expression has type tuple[int, int, ... <15 more items>], variable has type tuple[int, int, ... <10 more items>]) +t6: Tuple[int, int, int, int, int, int, int, int, int, int, int, int] = (1, 2, 3, 4, 5, 6, 7, 8, "str", "str", "str", "str", 1, 1, 1, 1, 1) # E: Incompatible types in assignment (expression has type "tuple[int, int, ... <15 more items>]", variable has type "tuple[int, int, ... <10 more items>]") [builtins fixtures/tuple.pyi]