ruff TC005: fix changes program behavior
Hypothesis Nemotron 3 Super predicted to fire fired 1×
keyword-only, positional-only, *args/**kwargs forwarding, defaults evaluated once
Program
Output
(no stdout) NameError: name 'TYPE_CHECKING' is not defined
None
- fired
- 1 before · 0 after
- runs
- each version twice, same file name, no network
Judge Nemotron 3 Ultra advisory real · high
The fix replaces the TYPE_CHECKING conditional block with an unconditional 'pass' statement, which changes the function's behavior from raising a NameError (when TYPE_CHECKING is undefined) to silently doing nothing. The documentation presents this rewrite as equivalent removal of dead code, but TYPE_CHECKING is not a built-in constant and the rule does not guard against its absence, making the fix unsafe for code that lacks the typing import.
Explanation Nemotron 3 Super unverified
The original function contains a conditional block that raises a NameError when executed because `TYPE_CHECKING` is undefined; this error prevents the `print` statement from running. The rewrite removes the condition and replaces it with an unconditional `pass`, allowing execution to proceed to the `print` call, which outputs `None`. Thus, the behavior changes from an error-induced crash to successful execution with output. This alters the program’s observable outcome, so the transformation is not semantics-preserving despite being labeled safe.
Reproduce
- file
prog.py(the before program)- minimized program
- r1-p008.py
- evidence sheet
- r1-p008.md
- regression fixture
- r1-p008.py the minimized program with a header stating the observed change, for the tool's test suite
python3 prog.py ruff check --preview --isolated --select TC005 --fix prog.py python3 prog.py
Upstream search GitHub issues Tavily Nemotron 3 Super + Ultra
TC005 fix · TC005 function parameter slash · ruff linting conditional block removal · Oracle behavior type checking guard
- duplicate astral-sh/ruff/issues/28868 same TC005 empty-type-checking-block fixer removing an if TYPE_CHECKING: pass block and changing behavior
- related astral-sh/ruff/issues/15681 same TYPE_CHECKING concept but false positives on imports with manual TYPE_CHECKING and __future__.annotations
- related astral-sh/ruff/pull/16669 TYPE_CHECKING symbol handling changes affecting type-checking blocks
- related astral-sh/ruff/issues/21921 flake8-type-checking rule about combining imports inside/outside TYPE_CHECKING blocks
- related astral-sh/ruff/issues/14538 TC003 rewrite issues with TYPE_CHECKING blocks causing syntax errors
- related astral-sh/ruff/issues/11103 rule suggestion for enforcing __future__.annotations with TYPE_CHECKING blocks
- related astral-sh/ruff/issues/9573 reharmonizing TCH rules with flake8-type-checking, same rule family
Details
- program
- Keyword-only, positional-only, *args/**kwargs forwarding with defaults
- hazard
- keyword-only, positional-only, *args/**kwargs forwarding, defaults evaluated once
- oracle
stdout before: stdout after: None exit 1 → 0 stderr before: NameError: name 'TYPE_CHECKING' is not defined stderr after: (none)- run
- 2026-10-17T20-39-34-299Z-g1ez-ruff-TC005
generated program (5 lines) and the fix's diff
--- orig.py 2026-10-17 16:39:44.636897831 -0400 +++ fixed.py 2026-10-17 16:39:45.025915003 -0400 @@ -1,5 +1,3 @@ def f(pos, /, kw=None, *args, **kwargs): - if TYPE_CHECKING: - pass return pos, kw, args, kwargs print(f(1, kw=2, extra=3))
rule documentation given to the models
# empty-type-checking-block (TC005)
Derived from the **flake8-type-checking** linter.
Fix is always available.
## What it does
Checks for an empty type-checking block.
## Why is this bad?
The type-checking block does not do anything and should be removed to avoid
confusion.
## Example
```python
from typing import TYPE_CHECKING
if TYPE_CHECKING:
pass
print("Hello, world!")
```
Use instead:
```python
print("Hello, world!")
```
## References
- [PEP 563: Runtime annotation resolution and `TYPE_CHECKING`](https://peps.python.org/pep-0563/#runtime-annotation-resolution-and-type-checking)