Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions mypy/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -724,6 +727,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)

Expand Down Expand Up @@ -776,6 +781,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)

Expand All @@ -800,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?
Expand Down
6 changes: 6 additions & 0 deletions mypy/server/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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())

Expand Down
110 changes: 110 additions & 0 deletions test-data/unit/daemon.test
Original file line number Diff line number Diff line change
Expand Up @@ -571,3 +571,113 @@ 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 --hide-error-codes
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

[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

[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
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

[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
2 changes: 2 additions & 0 deletions test-data/unit/fine-grained.test
Original file line number Diff line number Diff line change
Expand Up @@ -5390,6 +5390,7 @@ from enum import Enum

class C(Enum):
X = 0
[builtins fixtures/tuple.pyi]
[typing fixtures/typing-medium.pyi]
[out]
==
Expand Down Expand Up @@ -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]
==
Expand Down
3 changes: 3 additions & 0 deletions test-data/unit/fixtures/async_await.pyi
Original file line number Diff line number Diff line change
@@ -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: ...

Expand Down
5 changes: 5 additions & 0 deletions test-data/unit/fixtures/dataclasses.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand All @@ -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
Expand All @@ -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
Expand Down
5 changes: 5 additions & 0 deletions test-data/unit/fixtures/dict.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand All @@ -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
Expand All @@ -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
Expand Down
3 changes: 3 additions & 0 deletions test-data/unit/fixtures/list.pyi
Original file line number Diff line number Diff line change
@@ -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')

Expand All @@ -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
Expand Down
3 changes: 3 additions & 0 deletions test-data/unit/fixtures/plugin_attrs.pyi
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
16 changes: 16 additions & 0 deletions test-data/unit/fixtures/primitives.pyi
Original file line number Diff line number Diff line change
@@ -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')
Expand All @@ -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
Expand All @@ -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

Expand Down
2 changes: 2 additions & 0 deletions test-data/unit/fixtures/set.pyi
Original file line number Diff line number Diff line change
@@ -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')

Expand All @@ -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
Expand Down
Loading