fixhunt

ruff TC005

labelled unknown
Runs / 2026-10-17T20-39-34-299Z-g1ez-ruff-TC005ruff 0.17.12026-10-17 20:39 UTC8 programs × 2 round(s)16 programs, 12 fired, 12 fixed, 6 findings, 2 rejectedmodel cost $0.08

Analysis Nemotron 3 Super

Flags empty if TYPE_CHECKING blocks containing only pass statements.

Fix: Removes the entire if TYPE_CHECKING: block when its body consists solely of a pass statement, preserving surrounding indentation and code structure.

8 hazards
  • Removing the block may change line numbers, affecting debuggers or stack traces that rely on exact source locations.
  • If the block contains a trailing comment after pass, the comment will be deleted along with the block.
  • In nested contexts like class or function definitions, removing the block alters the indentation depth of subsequent lines, potentially breaking syntax if mixed tabs/spaces exist.
  • When the block follows a try/except/finally clause, its removal can change the visual grouping and lead to misinterpretation of exception handling scope.
  • If the block is the only statement in a suite (e.g., a lambda or one-liner if), deleting it may result in an empty suite, causing a syntax error.
  • In async functions, removing the block could affect the perceived coroutine structure if tools inspect raw source for await placement context.
  • When the block is adjacent to a multi-line statement (e.g., with implicit line continuation), its removal may alter the boundary detection for the continued line.
  • If the block is used as a placeholder for future type annotations (common in stubs), removing it deletes intentional design intent documented via comments nearby.

Findings

programoraclelabeljudgestatussummary
r1-p002fix-changes-behaviorlabelled safereal · highrelatedThe rule removes an `if TYPE_CHECKING:` block without ensuring `TYPE_CHECKING` is imported from `typing`. In the original code, the block is never executed bec…
r1-p003fix-changes-behaviorlabelled safereal · highrelatedThe fix removes the `if TYPE_CHECKING:` block without ensuring `TYPE_CHECKING` is imported from `typing`. The original code crashed with a NameError because `T…
r1-p004fix-changes-behaviorlabelled safereal · highduplicateThe fix removes the entire `if TYPE_CHECKING:` block, but the program does not import `TYPE_CHECKING` from `typing`. Before the fix, the block raises a `NameEr…
r1-p005fix-changes-behaviorlabelled safereal · highduplicateThe fix removes the `if TYPE_CHECKING:` guard but leaves a `pass` statement, changing the code from a no-op (when TYPE_CHECKING is undefined) to an uncondition…
r1-p007fix-changes-behaviorlabelled safereal · highduplicateThe rule removes an `if TYPE_CHECKING:` block without ensuring `TYPE_CHECKING` is imported from `typing`. In the original code, the `NameError` occurs at runti…
r1-p008fix-changes-behaviorlabelled safereal · highduplicateThe fix replaces the TYPE_CHECKING conditional block with an unconditional 'pass' statement, which changes the function's behavior from raising a NameError (wh…

Programs

idresulttitlehazard
r1-p001fix okContext manager without close() - object with write() but no __exit__context managers that are not files, objects with write() but no close()
r1-p002fix-changes-behaviorNested class/function definition with mixed tabs/spaces indentationIn nested contexts like class or function definitions, removing the block alters the indentation depth of subsequent lines, potentially breaking syntax if mixed tabs/spaces exist.
r1-p003fix-changes-behaviorMutable default argument aliased after rewritemutable default arguments and aliasing after a rewrite
r1-p004fix-changes-behaviorType annotation evaluated at runtime with typing-only importtype annotations evaluated at runtime, typing-only imports
r1-p005fix-changes-behaviorGenerator vs list: iterator consumed oncegenerators vs lists, iterators consumed once, lazy vs eager evaluation
r1-p006invalidMulti-line statement with implicit line continuation affected by block removalWhen the block is adjacent to a multi-line statement (e.g., with implicit line continuation), its removal may alter the boundary detection for the continued line.
r1-p007fix-changes-behaviorEvaluation order and side effects in expression mergingevaluation order and side effects when expressions are merged, duplicated or deleted
r1-p008fix-changes-behaviorKeyword-only, positional-only, *args/**kwargs forwarding with defaultskeyword-only, positional-only, *args/**kwargs forwarding, defaults evaluated once
r2-p001silent prediction offLambda with TYPE_CHECKING blockIf the block is the only statement in a suite (e.g., a lambda or one-liner if), deleting it may result in an empty suite, causing a syntax error.
r2-p002fix okStringIO context manager with write but no closecontext managers that are not files, objects with write() but no close()
r2-p003fix okBytes vs str in binary file write after TYPE_CHECKING blockbytes vs str, encoding and newline handling, text vs binary modes
r2-p004fix okException in finally clause after TYPE_CHECKING block deletionexceptions raised inside the rewritten code, finally/else clauses, exception chaining
r2-p005fix okPartial write in binary mode with truncated datafile modes and truncation, partial writes, non-str data passed to write
r2-p006silent prediction offEvaluation order: side effect in TYPE_CHECKING condition affects later assignmentevaluation order and side effects when expressions are merged, duplicated or deleted
r2-p007fix okPlaceholder for future type annotation with commentIf the block is used as a placeholder for future type annotations (common in stubs), removing it deletes intentional design intent documented via comments nearby.
r2-p008invalidDict ordering and duplicate keys after TYPE_CHECKING block removaldict ordering, duplicate keys, __hash__/__eq__ overrides, sets

Sources

r1-p001 · Context manager without close() - object with write() but no __exit__
1import io
2class Writer:
3 def __init__(self):
4 self.buf = ''
5 def write(self, s):
6 self.buf += s
7w = Writer()
8with w:
9 if TYPE_CHECKING:
10 pass
11print(w.buf)
--- orig.py	2026-10-17 16:39:41.450756856 -0400
+++ fixed.py	2026-10-17 16:39:41.845774376 -0400
@@ -6,6 +6,5 @@
         self.buf += s
 w = Writer()
 with w:
-    if TYPE_CHECKING:
-        pass
+    pass
 print(w.buf)
r1-p002 · Nested class/function definition with mixed tabs/spaces indentation
1def outer():
2 if True:
3 x = 1
4 else:
5 pass
6 if TYPE_CHECKING:
7 pass
8 print(x) # uses space indent; mixing with tab above causes IndentationError if block removed incorrectly
9outer()
--- orig.py	2026-10-17 16:39:42.056783730 -0400
+++ fixed.py	2026-10-17 16:39:42.439800691 -0400
@@ -3,7 +3,5 @@
 		x = 1
 	else:
 		pass
-	if TYPE_CHECKING:
-		pass
 	print(x)  # uses space indent; mixing with tab above causes IndentationError if block removed incorrectly
 outer()
r1-p003 · Mutable default argument aliased after rewrite
1def f(a=None):
2 if a is None:
3 a = []
4 if TYPE_CHECKING:
5 pass
6 a.append(1)
7 return a
8print(f())
9print(f())
--- orig.py	2026-10-17 16:39:42.534804899 -0400
+++ fixed.py	2026-10-17 16:39:42.912821638 -0400
@@ -1,8 +1,6 @@
 def f(a=None):
     if a is None:
         a = []
-    if TYPE_CHECKING:
-        pass
     a.append(1)
     return a
 print(f())
r1-p004 · Type annotation evaluated at runtime with typing-only import
1from typing import List
2if TYPE_CHECKING:
3 pass
4x: List[int] = []
5print(type(x).__name__)
--- orig.py	2026-10-17 16:39:43.012826066 -0400
+++ fixed.py	2026-10-17 16:39:43.396843045 -0400
@@ -1,5 +1,3 @@
 from typing import List
-if TYPE_CHECKING:
-    pass
 x: List[int] = []
 print(type(x).__name__)
r1-p005 · Generator vs list: iterator consumed once
1def gen():
2 if TYPE_CHECKING:
3 pass
4 yield 1
5 yield 2
6it = gen()
7print(next(it))
8print(list(it)) # second consumption: should be [2] if gen() is lazy; if broken, may be [] or error
--- orig.py	2026-10-17 16:39:43.505847865 -0400
+++ fixed.py	2026-10-17 16:39:43.895865110 -0400
@@ -1,6 +1,4 @@
 def gen():
-    if TYPE_CHECKING:
-        pass
     yield 1
     yield 2
 it = gen()
r1-p006 · Multi-line statement with implicit line continuation affected by block removal (generated program does not parse: Traceback (most recent call last):)
1total = (
2 1 +
3 2
4 if TYPE_CHECKING:
5 pass
6 + 3
7)
8print(total)
r1-p007 · Evaluation order and side effects in expression merging
1side = 0
2if TYPE_CHECKING:
3 pass
4side += 1
5print(side)
--- orig.py	2026-10-17 16:39:44.154876551 -0400
+++ fixed.py	2026-10-17 16:39:44.537893460 -0400
@@ -1,5 +1,3 @@
 side = 0
-if TYPE_CHECKING:
-    pass
 side += 1
 print(side)
r1-p008 · Keyword-only, positional-only, *args/**kwargs forwarding with defaults
1def f(pos, /, kw=None, *args, **kwargs):
2 if TYPE_CHECKING:
3 pass
4 return pos, kw, args, kwargs
5print(f(1, kw=2, extra=3))
--- 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))
r2-p001 · Lambda with TYPE_CHECKING block
1import typing
2f = lambda: [] if typing.TYPE_CHECKING else [print(1)]
3try:
4 f()
5except SyntaxError as e:
6 print(f'SyntaxError: {e}')
1
r2-p002 · StringIO context manager with write but no close
1import io, typing
2buf = io.StringIO()
3with buf:
4 if typing.TYPE_CHECKING:
5 pass
6 buf.write('hello')
7print(buf.getvalue())
--- orig.py	2026-10-17 16:39:49.486111068 -0400
+++ fixed.py	2026-10-17 16:39:49.873128023 -0400
@@ -1,7 +1,5 @@
 import io, typing
 buf = io.StringIO()
 with buf:
-    if typing.TYPE_CHECKING:
-        pass
     buf.write('hello')
 print(buf.getvalue())
r2-p003 · Bytes vs str in binary file write after TYPE_CHECKING block
1import typing
2with open('test.bin', 'wb') as f:
3 if typing.TYPE_CHECKING:
4 pass
5 f.write(b'hello' if not typing.TYPE_CHECKING else 'world')
6with open('test.bin', 'rb') as f:
7 print(f.read())
8import os
9os.remove('test.bin')
--- orig.py	2026-10-17 16:39:50.096137786 -0400
+++ fixed.py	2026-10-17 16:39:50.276145660 -0400
@@ -1,7 +1,5 @@
 import typing
 with open('test.bin', 'wb') as f:
-    if typing.TYPE_CHECKING:
-        pass
     f.write(b'hello' if not typing.TYPE_CHECKING else 'world')
 with open('test.bin', 'rb') as f:
     print(f.read())
b'hello'
r2-p004 · Exception in finally clause after TYPE_CHECKING block deletion
1import typing
2try:
3 if typing.TYPE_CHECKING:
4 pass
5 raise ValueError('bad')
6except ValueError as e:
7 print(f'Caught: {e}')
8finally:
9 print('finally runs')
10 if False:
11 raise RuntimeError('should not happen')
--- orig.py	2026-10-17 16:39:50.384150384 -0400
+++ fixed.py	2026-10-17 16:39:50.563158215 -0400
@@ -1,7 +1,5 @@
 import typing
 try:
-    if typing.TYPE_CHECKING:
-        pass
     raise ValueError('bad')
 except ValueError as e:
     print(f'Caught: {e}')
Caught: bad
finally runs
r2-p005 · Partial write in binary mode with truncated data
1import typing
2with open('test.bin', 'wb') as f:
3 if typing.TYPE_CHECKING:
4 pass
5 f.write(b'12345')
6 f.seek(2)
7 f.write(b'99')
8with open('test.bin', 'rb') as f:
9 print(f.read())
10import os
11os.remove('test.bin')
--- orig.py	2026-10-17 16:39:50.671162939 -0400
+++ fixed.py	2026-10-17 16:39:50.850170769 -0400
@@ -1,7 +1,5 @@
 import typing
 with open('test.bin', 'wb') as f:
-    if typing.TYPE_CHECKING:
-        pass
     f.write(b'12345')
     f.seek(2)
     f.write(b'99')
b'12995'
r2-p006 · Evaluation order: side effect in TYPE_CHECKING condition affects later assignment
1import typing
2counter = 0
3def inc():
4 global counter
5 counter += 1
6 return counter
7if typing.TYPE_CHECKING and inc():
8 x = 1
9else:
10 x = 2
11print(f'x={x}, counter={counter}')
x=2, counter=0
r2-p007 · Placeholder for future type annotation with comment
1import typing
2# TODO: Add proper type for config when module stabilizes
3if typing.TYPE_CHECKING:
4 pass
5config = {} # runtime dict, will be typed later
6print(f'config={config}')
--- orig.py	2026-10-17 16:39:51.109182092 -0400
+++ fixed.py	2026-10-17 16:39:51.288189910 -0400
@@ -1,6 +1,4 @@
 import typing
 # TODO: Add proper type for config when module stabilizes
-if typing.TYPE_CHECKING:
-    pass
 config = {}  # runtime dict, will be typed later
 print(f'config={config}')
config={}
r2-p008 · Dict ordering and duplicate keys after TYPE_CHECKING block removal (generated program does not parse: Traceback (most recent call last):)
1import typing
2d = {}
3if typing.TYPE_CHECKING:
4 pass
5d['a'] = 1
6d['b'] = 2
7d['a'] = 3 # duplicate key
8for k, v in d.items():
9 print(f'{k}:{v}', end=' ')}
10print()