Adverse interaction between `unreachable` code, `type: ignore[...]`, and `pass` or `...`
Bug Report
Both pass statements and the ellipsis (...) are treated as non-statements by mypy, leading to unexpected handling of an unreachable cases.
To Reproduce
Run the following with --strict --warn-unreachable:
def func1(value: int) -> None:
if not isinstance(value, int):
pass # type: ignore[unreachable] # error: [unused-ignore]
print("there was a problem ...") # error: [unreachable]
Changing pass to a literal ellipsis (...) also reproduces this problem.
(Motivation: since # type: ignore[...] directives must appear on the same line they affect, placing the # type directive on a pass statement can avoid very long lines.)
Expected Behavior
mypy should treat pass as the unreachable statement in this case.
Actual Behavior
mypy's output is:
main.py:3: error: Unused "type: ignore" comment [unused-ignore]
main.py:4: error: Statement is unreachable [unreachable]
Found 2 errors in 1 file (checked 1 source file)
Your Environment
- Mypy version used: 1.5.1
- Mypy command-line flags:
--strict --warn-unreachable - Mypy configuration options from
mypy.ini(and other config files): none - Python version used: 3.8, 3.11
I also ran into this problem and wanted to share the use case leading me to this issue. Let's assume we have a Python module that contains pytest test cases. We want to skip all test cases in the module, so we use pytest.skip as follows:
import pytest
pytest.skip("Skip tests due to XYZ", allow_module_level=True)
def test_abc() -> None:
...
Mypy will report that the line after pytest.skip is unreachable. However, adding type: ignore[unreachable] simply converts the warning into unused-ignore, as reported by the OP.
As a workaround, I was able to add type: ignore[unreachable, unused-ignore]. This is obviously no big deal, but the behavior is a bit surprising.