From aee18968dd6203892aa324f611e73388178d1472 Mon Sep 17 00:00:00 2001 From: Charlie Denton Date: Sat, 4 Mar 2023 17:38:50 +0000 Subject: [PATCH 1/8] Add test to demonstrate issue #9655 This test currently fails with this error: AssertionError: Command 3 (dmypy check -- bar.py) did not give expected output --- Captured stderr call --- Expected: bar.py:2: error: Unused "type: ignore" comment (diff) == Return code: 1 (diff) Actual: (empty) It demonstrates a bug that when an module is removed using `FineGrainedBuildManager.update` because it is not "seen" by `fine_grained_increment_follow_imports`, then "unused type: ignore" warnings disappear from subsequent checks. Ref: https://github.com/python/mypy/issues/9655 --- test-data/unit/daemon.test | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test-data/unit/daemon.test b/test-data/unit/daemon.test index 18a03a92207d..84ba877a9971 100644 --- a/test-data/unit/daemon.test +++ b/test-data/unit/daemon.test @@ -571,3 +571,20 @@ class A: x: int class B: x: int + +[case testUnusedTypeIgnorePreservedOnRerun] +-- Regression test for https://github.com/python/mypy/issues/9655 +$ dmypy start -- --warn-unused-ignores --no-error-summary +Daemon started +$ dmypy check -- bar.py +bar.py:2: error: Unused "type: ignore" comment +== Return code: 1 +$ dmypy check -- bar.py +bar.py:2: error: Unused "type: ignore" comment +== Return code: 1 + +[file foo/__init__.py] +[file foo/empty.py] +[file bar.py] +from foo.empty import * +a = 1 # type: ignore From d2d8a499d2e5f81c4ae14ba2ecd9c88d1274a532 Mon Sep 17 00:00:00 2001 From: Charlie Denton Date: Sun, 12 Mar 2023 22:23:51 +0000 Subject: [PATCH 2/8] Prove ignores without error codes also disappear This test fails with the error: AssertionError: Command 3 (dmypy check -- bar.py) did not give expected output --- Captured stderr call --- Expected: bar.py:2: error: "type: ignore" comment without error code [ignore-without-code] (diff) == Return code: 1 (diff) Actual: (empty) This test illustrates that '"type: ignore" comment without error code' errors currently disappear in the same way that 'Unused "type: ignore"' errors do as described in #9655. Ref: https://github.com/python/mypy/issues/9655 --- test-data/unit/daemon.test | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test-data/unit/daemon.test b/test-data/unit/daemon.test index 84ba877a9971..e02e27340a8e 100644 --- a/test-data/unit/daemon.test +++ b/test-data/unit/daemon.test @@ -588,3 +588,20 @@ bar.py:2: error: Unused "type: ignore" comment [file bar.py] from foo.empty import * a = 1 # type: ignore + +[case testTypeIgnoreWithoutCodePreservedOnRerun] +-- Regression test for https://github.com/python/mypy/issues/9655 +$ dmypy start -- --enable-error-code ignore-without-code --no-error-summary +Daemon started +$ dmypy check -- bar.py +bar.py:2: error: "type: ignore" comment without error code [ignore-without-code] +== Return code: 1 +$ dmypy check -- bar.py +bar.py:2: error: "type: ignore" comment without error code [ignore-without-code] +== Return code: 1 + +[file foo/__init__.py] +[file foo/empty.py] +[file bar.py] +from foo.empty import * +a = 1 # type: ignore From 437c90f0ff0b5b75d9fbc3ba4201dfc6867f1fc2 Mon Sep 17 00:00:00 2001 From: Charlie Denton Date: Sun, 12 Mar 2023 23:25:29 +0000 Subject: [PATCH 3/8] Prove possibly-undefined errors disappear This test fails with the error: AssertionError: Command 3 (dmypy check -- bar.py) did not give expected output --- Captured stderr call --- Expected: bar.py:4: error: Name "a" may be undefined [possibly-undefined] (diff) == Return code: 1 (diff) Actual: (empty) This test illustrates that possibly-undefined errors currently disappear in the same way that 'Unused "type: ignore"' errors do as described in #9655. Ref: https://github.com/python/mypy/issues/9655 --- test-data/unit/daemon.test | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test-data/unit/daemon.test b/test-data/unit/daemon.test index e02e27340a8e..c119b2a0fb6b 100644 --- a/test-data/unit/daemon.test +++ b/test-data/unit/daemon.test @@ -605,3 +605,22 @@ bar.py:2: error: "type: ignore" comment without error code [ignore-without-code [file bar.py] from foo.empty import * a = 1 # type: ignore + +[case testPossiblyUndefinedVarsPreservedAfterUpdate] +-- Regression test for https://github.com/python/mypy/issues/9655 +$ dmypy start -- --enable-error-code possibly-undefined --no-error-summary +Daemon started +$ dmypy check -- bar.py +bar.py:4: error: Name "a" may be undefined [possibly-undefined] +== Return code: 1 +$ dmypy check -- bar.py +bar.py:4: error: Name "a" may be undefined [possibly-undefined] +== Return code: 1 + +[file foo/__init__.py] +[file foo/empty.py] +[file bar.py] +from foo.empty import * +if False: + a = 1 +a From 4c6bc1315af5ae76022a63140c6c7c05f6d3f403 Mon Sep 17 00:00:00 2001 From: Charlie Denton Date: Fri, 31 Mar 2023 23:30:08 +0100 Subject: [PATCH 4/8] Test run-running dmypy after a file is altered These tests show how some errors disappear on a re-run of dmypy after a file is altered. --- test-data/unit/daemon.test | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/test-data/unit/daemon.test b/test-data/unit/daemon.test index c119b2a0fb6b..f29016ce053c 100644 --- a/test-data/unit/daemon.test +++ b/test-data/unit/daemon.test @@ -574,7 +574,7 @@ class B: [case testUnusedTypeIgnorePreservedOnRerun] -- Regression test for https://github.com/python/mypy/issues/9655 -$ dmypy start -- --warn-unused-ignores --no-error-summary +$ dmypy start -- --warn-unused-ignores --no-error-summary --hide-error-codes Daemon started $ dmypy check -- bar.py bar.py:2: error: Unused "type: ignore" comment @@ -606,6 +606,42 @@ bar.py:2: error: "type: ignore" comment without error code [ignore-without-code from foo.empty import * a = 1 # type: ignore +[case testUnusedTypeIgnorePreservedAfterChange] +-- Regression test for https://github.com/python/mypy/issues/9655 +$ dmypy start -- --warn-unused-ignores --no-error-summary --hide-error-codes +Daemon started +$ dmypy check -- bar.py +bar.py:2: error: Unused "type: ignore" comment +== Return code: 1 +$ echo '' >> bar.py +$ dmypy check -- bar.py +bar.py:2: error: Unused "type: ignore" comment +== Return code: 1 + +[file foo/__init__.py] +[file foo/empty.py] +[file bar.py] +from foo.empty import * +a = 1 # type: ignore + +[case testTypeIgnoreWithoutCodePreservedAfterChange] +-- Regression test for https://github.com/python/mypy/issues/9655 +$ dmypy start -- --enable-error-code ignore-without-code --no-error-summary +Daemon started +$ dmypy check -- bar.py +bar.py:2: error: "type: ignore" comment without error code [ignore-without-code] +== Return code: 1 +$ echo '' >> bar.py +$ dmypy check -- bar.py +bar.py:2: error: "type: ignore" comment without error code [ignore-without-code] +== Return code: 1 + +[file foo/__init__.py] +[file foo/empty.py] +[file bar.py] +from foo.empty import * +a = 1 # type: ignore + [case testPossiblyUndefinedVarsPreservedAfterUpdate] -- Regression test for https://github.com/python/mypy/issues/9655 $ dmypy start -- --enable-error-code possibly-undefined --no-error-summary From e2b9520b5de1028a267c156320d49955e60eb2f2 Mon Sep 17 00:00:00 2001 From: Charlie Denton Date: Thu, 20 Jul 2023 15:24:52 +0100 Subject: [PATCH 5/8] Fix disappearing errors when re-running dmypy check This which fixes issue https://github.com/python/mypy/issues/9655 wherein some types of error would be lost when a file was re-processed by dmypy. Regression tests are also included. This also fixes another error where sometimes files would not be re-processed by dmypy if the only error in the file was either "unused type ignore" or "ignore without code". --- mypy/errors.py | 4 ++++ mypy/server/update.py | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/mypy/errors.py b/mypy/errors.py index 4e62a48aeb27..4cdeb54f823a 100644 --- a/mypy/errors.py +++ b/mypy/errors.py @@ -724,6 +724,8 @@ def generate_unused_ignore_errors(self, file: str) -> None: blocker=False, only_once=False, allow_dups=False, + origin=(self.file, [line]), + target=self.target_module, ) self._add_error_info(file, info) @@ -776,6 +778,8 @@ def generate_ignore_without_code_errors( blocker=False, only_once=False, allow_dups=False, + origin=(self.file, [line]), + target=self.target_module, ) self._add_error_info(file, info) diff --git a/mypy/server/update.py b/mypy/server/update.py index 0cc7a2229514..0371d5d40266 100644 --- a/mypy/server/update.py +++ b/mypy/server/update.py @@ -667,6 +667,8 @@ def restore(ids: list[str]) -> None: state.type_check_first_pass() state.type_check_second_pass() state.detect_possibly_undefined_vars() + state.generate_unused_ignore_notes() + state.generate_ignore_without_code_notes() t2 = time.time() state.finish_passes() t3 = time.time() @@ -1028,6 +1030,10 @@ def key(node: FineGrainedDeferredNode) -> int: if graph[module_id].type_checker().check_second_pass(): more = True + graph[module_id].detect_possibly_undefined_vars() + graph[module_id].generate_unused_ignore_notes() + graph[module_id].generate_ignore_without_code_notes() + if manager.options.export_types: manager.all_types.update(graph[module_id].type_map()) From cca70fc8610b30a562fa67dbb2b47320ec8438bf Mon Sep 17 00:00:00 2001 From: Charlie Denton Date: Wed, 12 Apr 2023 16:02:45 +0100 Subject: [PATCH 6/8] Add a failing test for type ignores in dmypy This catches a regression caused by the previous commits where "type: ignore" comments are erroneously marked as unused in re-runs of dmypy. As far as I can tell, this only happens in modules which contain an import that we don't know how to type (such as a module which does not exist), and a submodule which is unused. --- test-data/unit/daemon.test | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test-data/unit/daemon.test b/test-data/unit/daemon.test index f29016ce053c..d772635ac027 100644 --- a/test-data/unit/daemon.test +++ b/test-data/unit/daemon.test @@ -660,3 +660,24 @@ from foo.empty import * if False: a = 1 a + +[case testReturnTypeIgnoreAfterUnknownImport] +-- Return type ignores after unknown imports and unused modules are respected on the second pass. +$ dmypy start -- --warn-unused-ignores --no-error-summary +Daemon started +$ dmypy check -- foo.py +foo.py:2: error: Cannot find implementation or library stub for module named "a_module_which_does_not_exist" [import-not-found] +foo.py:2: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports +== Return code: 1 +$ dmypy check -- foo.py +foo.py:2: error: Cannot find implementation or library stub for module named "a_module_which_does_not_exist" [import-not-found] +foo.py:2: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports +== Return code: 1 + +[file unused/__init__.py] +[file unused/empty.py] +[file foo.py] +from unused.empty import * +import a_module_which_does_not_exist +def is_foo() -> str: + return True # type: ignore From 84271b063558b9c5481aa236190c42038a9b039c Mon Sep 17 00:00:00 2001 From: Charlie Denton Date: Sat, 14 Oct 2023 21:08:29 +0100 Subject: [PATCH 7/8] Record ignored errors from non-ignored files Before this change, fine-grained builds could spuriously mark ignored legitimate errors as "unused ignores". By keeping track of these ignored errors we ensure that enough analysis is done to know that the ignored lines are actually useful. We have to change is_errors_for_file so that we don't consider files as faulty when all of their errors were hidden. --- mypy/errors.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mypy/errors.py b/mypy/errors.py index 4cdeb54f823a..427659253540 100644 --- a/mypy/errors.py +++ b/mypy/errors.py @@ -503,6 +503,9 @@ def add_error_info(self, info: ErrorInfo) -> None: self.used_ignored_lines[file][scope_line].append( (info.code or codes.MISC).code ) + if file not in self.ignored_files: + info.hidden = True + self._add_error_info(file, info) return if file in self.ignored_files: return @@ -804,8 +807,9 @@ def blocker_module(self) -> str | None: return None def is_errors_for_file(self, file: str) -> bool: - """Are there any errors for the given file?""" - return file in self.error_info_map + """Are there any visible errors for the given file?""" + errors = self.error_info_map.get(file, ()) + return any(error.hidden is False for error in errors) def prefer_simple_messages(self) -> bool: """Should we generate simple/fast error messages? From 4c37dac8f2725a2377e3454c9bcb1b6fb729203a Mon Sep 17 00:00:00 2001 From: David Seddon Date: Mon, 18 Dec 2023 18:21:29 +0000 Subject: [PATCH 8/8] Make tests compatible with change (WIP) --- test-data/unit/fine-grained.test | 2 ++ test-data/unit/fixtures/async_await.pyi | 3 +++ test-data/unit/fixtures/dataclasses.pyi | 5 +++++ test-data/unit/fixtures/dict.pyi | 5 +++++ test-data/unit/fixtures/list.pyi | 3 +++ test-data/unit/fixtures/plugin_attrs.pyi | 3 +++ test-data/unit/fixtures/primitives.pyi | 16 ++++++++++++++++ test-data/unit/fixtures/set.pyi | 2 ++ test-data/unit/fixtures/tuple.pyi | 8 +++++++- test-data/unit/fixtures/typing-medium.pyi | 3 +++ test-data/unit/fixtures/typing-typeddict.pyi | 2 ++ 11 files changed, 51 insertions(+), 1 deletion(-) diff --git a/test-data/unit/fine-grained.test b/test-data/unit/fine-grained.test index 68f72a2aa992..6cae8a81bf51 100644 --- a/test-data/unit/fine-grained.test +++ b/test-data/unit/fine-grained.test @@ -5390,6 +5390,7 @@ from enum import Enum class C(Enum): X = 0 +[builtins fixtures/tuple.pyi] [typing fixtures/typing-medium.pyi] [out] == @@ -5486,6 +5487,7 @@ C = Enum('C', 'X Y') from enum import Enum C = Enum('C', 'X') +[builtins fixtures/tuple.pyi] [typing fixtures/typing-medium.pyi] [out] == diff --git a/test-data/unit/fixtures/async_await.pyi b/test-data/unit/fixtures/async_await.pyi index 96ade881111b..28daa0321947 100644 --- a/test-data/unit/fixtures/async_await.pyi +++ b/test-data/unit/fixtures/async_await.pyi @@ -1,9 +1,12 @@ import typing +from typing_extensions import override T = typing.TypeVar('T') U = typing.TypeVar('U') class list(typing.Sequence[T]): + @override def __iter__(self) -> typing.Iterator[T]: ... + @override def __getitem__(self, i: int) -> T: ... def __contains__(self, item: object) -> bool: ... diff --git a/test-data/unit/fixtures/dataclasses.pyi b/test-data/unit/fixtures/dataclasses.pyi index 059c853a621f..29f87ae97e62 100644 --- a/test-data/unit/fixtures/dataclasses.pyi +++ b/test-data/unit/fixtures/dataclasses.pyi @@ -3,6 +3,7 @@ from typing import ( Generic, Iterator, Iterable, Mapping, Optional, Sequence, Tuple, TypeVar, Union, overload, ) +from typing_extensions import override _T = TypeVar('_T') _U = TypeVar('_U') @@ -29,8 +30,10 @@ class dict(Mapping[KT, VT]): def __init__(self, **kwargs: VT) -> None: pass @overload def __init__(self, arg: Iterable[Tuple[KT, VT]], **kwargs: VT) -> None: pass + @override def __getitem__(self, key: KT) -> VT: pass def __setitem__(self, k: KT, v: VT) -> None: pass + @override def __iter__(self) -> Iterator[KT]: pass def __contains__(self, item: object) -> int: pass def update(self, a: Mapping[KT, VT]) -> None: pass @@ -42,7 +45,9 @@ class dict(Mapping[KT, VT]): class list(Generic[_T], Sequence[_T]): def __contains__(self, item: object) -> int: pass + @override def __getitem__(self, key: int) -> _T: pass + @override def __iter__(self) -> Iterator[_T]: pass class function: pass diff --git a/test-data/unit/fixtures/dict.pyi b/test-data/unit/fixtures/dict.pyi index 19d175ff79ab..dfb7fab13422 100644 --- a/test-data/unit/fixtures/dict.pyi +++ b/test-data/unit/fixtures/dict.pyi @@ -5,6 +5,7 @@ import _typeshed from typing import ( TypeVar, Generic, Iterable, Iterator, Mapping, Tuple, overload, Optional, Union, Sequence ) +from typing_extensions import override T = TypeVar('T') KT = TypeVar('KT') @@ -23,8 +24,10 @@ class dict(Mapping[KT, VT]): def __init__(self, **kwargs: VT) -> None: pass @overload def __init__(self, arg: Iterable[Tuple[KT, VT]], **kwargs: VT) -> None: pass + @override def __getitem__(self, key: KT) -> VT: pass def __setitem__(self, k: KT, v: VT) -> None: pass + @override def __iter__(self) -> Iterator[KT]: pass def __contains__(self, item: object) -> int: pass def update(self, a: SupportsKeysAndGetItem[KT, VT]) -> None: pass @@ -46,7 +49,9 @@ class str: pass # for keyword argument key type class bytes: pass class list(Sequence[T]): # needed by some test cases + @override def __getitem__(self, x: int) -> T: pass + @override def __iter__(self) -> Iterator[T]: pass def __mul__(self, x: int) -> list[T]: pass def __contains__(self, item: object) -> bool: pass diff --git a/test-data/unit/fixtures/list.pyi b/test-data/unit/fixtures/list.pyi index 90fbabe8bc92..ac5b7e49b147 100644 --- a/test-data/unit/fixtures/list.pyi +++ b/test-data/unit/fixtures/list.pyi @@ -1,6 +1,7 @@ # Builtins stub used in list-related test cases. from typing import TypeVar, Generic, Iterable, Iterator, Sequence, overload +from typing_extensions import override T = TypeVar('T') @@ -15,11 +16,13 @@ class list(Sequence[T]): def __init__(self) -> None: pass @overload def __init__(self, x: Iterable[T]) -> None: pass + @override def __iter__(self) -> Iterator[T]: pass def __len__(self) -> int: pass def __contains__(self, item: object) -> bool: pass def __add__(self, x: list[T]) -> list[T]: pass def __mul__(self, x: int) -> list[T]: pass + @override def __getitem__(self, x: int) -> T: pass def __setitem__(self, x: int, v: T) -> None: pass def append(self, x: T) -> None: pass diff --git a/test-data/unit/fixtures/plugin_attrs.pyi b/test-data/unit/fixtures/plugin_attrs.pyi index 57e5ecd1b2bc..ffaa82798ae7 100644 --- a/test-data/unit/fixtures/plugin_attrs.pyi +++ b/test-data/unit/fixtures/plugin_attrs.pyi @@ -1,5 +1,6 @@ # Builtins stub used to support attrs plugin tests. from typing import Union, overload, Generic, Sequence, TypeVar, Type, Iterable, Iterator +from typing_extensions import override class object: def __init__(self) -> None: pass @@ -31,6 +32,8 @@ T = TypeVar("T") Tco = TypeVar('Tco', covariant=True) class tuple(Sequence[Tco], Generic[Tco]): def __new__(cls: Type[T], iterable: Iterable[Tco] = ...) -> T: ... + @override def __iter__(self) -> Iterator[Tco]: pass def __contains__(self, item: object) -> bool: pass + @override def __getitem__(self, x: int) -> Tco: pass diff --git a/test-data/unit/fixtures/primitives.pyi b/test-data/unit/fixtures/primitives.pyi index 63128a8ae03d..bc75aa70b6ed 100644 --- a/test-data/unit/fixtures/primitives.pyi +++ b/test-data/unit/fixtures/primitives.pyi @@ -1,6 +1,7 @@ # builtins stub with non-generic primitive types import _typeshed from typing import Generic, TypeVar, Sequence, Iterator, Mapping, Iterable, Tuple, Union +from typing_extensions import override T = TypeVar('T') V = TypeVar('V') @@ -27,35 +28,48 @@ class complex: class bool(int): pass class str(Sequence[str]): def __add__(self, s: str) -> str: pass + @override def __iter__(self) -> Iterator[str]: pass def __contains__(self, other: object) -> bool: pass + @override def __getitem__(self, item: int) -> str: pass def format(self, *args: object, **kwargs: object) -> str: pass class bytes(Sequence[int]): + @override def __iter__(self) -> Iterator[int]: pass def __contains__(self, other: object) -> bool: pass + @override def __getitem__(self, item: int) -> int: pass class bytearray(Sequence[int]): def __init__(self, x: bytes) -> None: pass + @override def __iter__(self) -> Iterator[int]: pass def __contains__(self, other: object) -> bool: pass + @override def __getitem__(self, item: int) -> int: pass class memoryview(Sequence[int]): def __init__(self, x: bytes) -> None: pass + @override def __iter__(self) -> Iterator[int]: pass def __contains__(self, other: object) -> bool: pass + @override def __getitem__(self, item: int) -> int: pass class tuple(Generic[T]): def __contains__(self, other: object) -> bool: pass class list(Sequence[T]): + @override def __iter__(self) -> Iterator[T]: pass def __contains__(self, other: object) -> bool: pass + @override def __getitem__(self, item: int) -> T: pass class dict(Mapping[T, V]): + @override def __iter__(self) -> Iterator[T]: pass class set(Iterable[T]): + @override def __iter__(self) -> Iterator[T]: pass class frozenset(Iterable[T]): + @override def __iter__(self) -> Iterator[T]: pass class function: pass class ellipsis: pass @@ -64,7 +78,9 @@ class range(Sequence[int]): def __init__(self, __x: int, __y: int = ..., __z: int = ...) -> None: pass def count(self, value: int) -> int: pass def index(self, value: int) -> int: pass + @override def __getitem__(self, i: int) -> int: pass + @override def __iter__(self) -> Iterator[int]: pass def __contains__(self, other: object) -> bool: pass diff --git a/test-data/unit/fixtures/set.pyi b/test-data/unit/fixtures/set.pyi index 71d3bd2eee18..cbf801f0551a 100644 --- a/test-data/unit/fixtures/set.pyi +++ b/test-data/unit/fixtures/set.pyi @@ -1,6 +1,7 @@ # Builtins stub used in set-related test cases. from typing import TypeVar, Generic, Iterator, Iterable, Set +from typing_extensions import override T = TypeVar('T') @@ -19,6 +20,7 @@ class ellipsis: pass class set(Iterable[T], Generic[T]): def __init__(self, iterable: Iterable[T] = ...) -> None: ... + @override def __iter__(self) -> Iterator[T]: pass def __contains__(self, item: object) -> bool: pass def __ior__(self, x: Set[T]) -> None: pass diff --git a/test-data/unit/fixtures/tuple.pyi b/test-data/unit/fixtures/tuple.pyi index e270f3d79d3e..3202d46c841b 100644 --- a/test-data/unit/fixtures/tuple.pyi +++ b/test-data/unit/fixtures/tuple.pyi @@ -2,7 +2,7 @@ import _typeshed from typing import Iterable, Iterator, TypeVar, Generic, Sequence, Optional, overload, Tuple, Type - +from typing_extensions import override T = TypeVar("T") Tco = TypeVar('Tco', covariant=True) @@ -14,11 +14,14 @@ class type: def __call__(self, *a: object) -> object: pass class tuple(Sequence[Tco], Generic[Tco]): def __new__(cls: Type[T], iterable: Iterable[Tco] = ...) -> T: ... + @override def __iter__(self) -> Iterator[Tco]: pass def __contains__(self, item: object) -> bool: pass @overload + @override def __getitem__(self, x: int) -> Tco: pass @overload + @override def __getitem__(self, x: slice) -> Tuple[Tco, ...]: ... def __mul__(self, n: int) -> Tuple[Tco, ...]: pass def __rmul__(self, n: int) -> Tuple[Tco, ...]: pass @@ -41,10 +44,13 @@ class bytearray: pass class list(Sequence[T], Generic[T]): @overload + @override def __getitem__(self, i: int) -> T: ... @overload + @override def __getitem__(self, s: slice) -> list[T]: ... def __contains__(self, item: object) -> bool: ... + @override def __iter__(self) -> Iterator[T]: ... def isinstance(x: object, t: type) -> bool: pass diff --git a/test-data/unit/fixtures/typing-medium.pyi b/test-data/unit/fixtures/typing-medium.pyi index 03be1d0a664d..cbb210283a50 100644 --- a/test-data/unit/fixtures/typing-medium.pyi +++ b/test-data/unit/fixtures/typing-medium.pyi @@ -6,6 +6,8 @@ # Many of the definitions have special handling in the type checker, so they # can just be initialized to anything. +from typing_extensions import override + cast = 0 overload = 0 Any = 0 @@ -49,6 +51,7 @@ class Iterator(Iterable[T_co], Protocol): def __next__(self) -> T_co: pass class Generator(Iterator[T], Generic[T, U, V]): + @override def __iter__(self) -> 'Generator[T, U, V]': pass class Sequence(Iterable[T_co]): diff --git a/test-data/unit/fixtures/typing-typeddict.pyi b/test-data/unit/fixtures/typing-typeddict.pyi index 24a2f1328981..79afebb8e3d1 100644 --- a/test-data/unit/fixtures/typing-typeddict.pyi +++ b/test-data/unit/fixtures/typing-typeddict.pyi @@ -7,6 +7,7 @@ # can just be initialized to anything. from abc import ABCMeta +from typing_extensions import override cast = 0 assert_type = 0 @@ -63,6 +64,7 @@ class Mapping(Iterable[T], Generic[T, T_co], metaclass=ABCMeta): class _TypedDict(Mapping[str, object]): # Needed to make this class non-abstract. It is explicitly declared abstract in # typeshed, but we don't want to import abc here, as it would slow down the tests. + @override def __iter__(self) -> Iterator[str]: ... def copy(self: T) -> T: ... # Using NoReturn so that only calls using the plugin hook can go through. pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy