fixhunt

ruff TC008

labelled unknown
Runs / 2026-10-17T20-45-09-298Z-olks-ruff-TC008ruff 0.17.12026-10-17 20:45 UTC8 programs × 2 round(s)8 programs, 5 fired, 5 fixed, 1 findings, 0 rejectedmodel cost $0.01

Analysis Nemotron 3 Super

Flags unnecessary quotes in PEP 613 explicit type aliases and PEP 695 type statements when the quoted content is a valid type expression without forward references.

Fix: Removes the outer double quotes around the type expression while preserving whitespace and inner structure, converting e.g., "int | None" to int | None.

8 hazards
  • Rewriting may break code if the quoted string contains a comment, as the fix does not preserve comments inside the quotes.
  • If the type expression relies on a name only available via TYPE_CHECKING imports, removing quotes could cause a NameError at runtime.
  • In stub files, removing quotes might violate stub-only type contracts where the unquoted form is not available at runtime.
  • If the quoted expression includes a forward reference to a class defined later in the same module, the fix assumes it is defined, which may not hold during execution.
  • The fix does not account for string concatenation inside quotes (e.g., "int" "|" "None"), leaving it unchanged but potentially misleading users.
  • If the quoted string contains escaped quotes (e.g., "\"int\" |"), the fix incorrectly strips outer quotes, corrupting the expression.
  • When the type alias is used in a runtime context (e.g., isinstance), removing quotes could alter behavior if the string was intentionally used as a fallback.
  • The fix may interfere with tools that inspect source strings directly, expecting the quotes to be present for metadata or code generation.

Findings

programoraclelabeljudgestatussummary
r1-p005fix-changes-behaviorlabelled safereal · mediumno matchThe rule removes quotes from a PEP 613 type alias that uses concatenated string literals ('int' '|' 'None'), rewriting it to the unquoted union int|None. At ru…

Programs

idresulttitlehazard
r1-p001silent prediction offMutable Default Arguments & Aliasing After RewriteTC008 removes quotes from 'list[int]' used as a function default argument; if the alias points to a mutable object shared across calls, removing quotes doesn't affect runtime behavior—but misleads dev
r1-p002fix okBytes vs Str Encoding & Newline HandlingRewriting 'bytes' to bare identifier breaks code that relied on the string being a type annotation for bytes literals; if misread as str, encoding assumptions fail.
r1-p003fix okForward Reference Assumed Defined LaterRule removes quotes from 'SomeClass' assuming it's defined, but if SomeClass is defined later in the module, the bare name causes NameError at runtime.
r1-p004fix okpathlib vs os.path Behavior on Relative PathsRewriting 'Path' to bare identifier in alias breaks if user mistakenly uses os.path functions on the type; but since it's a type alias, no runtime effect—yet misleading in static analysis.
r1-p005fix-changes-behavior prediction offString Concatenation Inside Quotes Left UnchangedRule does not rewrite '"int" "|" "None"' (concatenated strings), so alias remains quoted; if developer expects it to be unquoted, they may misuse it.
r1-p006fix okTool Expecting Quotes for Metadata InspectionA tool that scans source for quoted type aliases to extract documentation expects quotes; after fix, it fails to detect the alias.
r1-p007silent prediction offString Formatting Edge Cases: % , format(), f-stringsIf the quoted type alias is used in an f-string or % formatting, removing quotes changes behavior: e.g., f'{ListInt}' becomes f'{list[int]}' which may eval or raise.
r1-p008silent prediction offEvaluation Order & Side Effects in Merged ExpressionsIf the quoted expression has side effects (e.g., function call), removing quotes doesn't change evaluation—but if the alias is reused in multiple contexts, duplication may cause unexpected behavior.

Sources

r1-p001 · Mutable Default Arguments & Aliasing After Rewrite
1from typing import TypeAlias
2ListInt: TypeAlias = "list[int]"
3def f(x=ListInt()):
4 x.append(1)
5 return x
6print(f())
7print(f())
r1-p002 · Bytes vs Str Encoding & Newline Handling
1from typing import TypeAlias
2MyBytes: TypeAlias = "bytes"
3def g(b: MyBytes) -> str:
4 return b.decode('utf-8')
5try:
6 print(g(b'hello\n'))
7except Exception as e:
8 print(type(e).__name__, e)
--- orig.py	2026-10-17 16:45:18.878566251 -0400
+++ fixed.py	2026-10-17 16:45:19.063571336 -0400
@@ -1,5 +1,5 @@
 from typing import TypeAlias
-MyBytes: TypeAlias = "bytes"
+MyBytes: TypeAlias = bytes
 def g(b: MyBytes) -> str:
     return b.decode('utf-8')
 try:
hello
r1-p003 · Forward Reference Assumed Defined Later
1type OptCls = "SomeClass"
2class SomeClass:
3 pass
4inst: OptCls = SomeClass()
5print(type(inst).__name__)
--- orig.py	2026-10-17 16:45:19.193574906 -0400
+++ fixed.py	2026-10-17 16:45:19.362579547 -0400
@@ -1,4 +1,4 @@
-type OptCls = "SomeClass"
+type OptCls = SomeClass
 class SomeClass:
     pass
 inst: OptCls = SomeClass()
SomeClass
r1-p004 · pathlib vs os.path Behavior on Relative Paths
1from typing import TypeAlias
2from pathlib import Path
3P: TypeAlias = "Path"
4p: P = Path('.')
5print(p.exists())
6print(p.is_absolute())
--- orig.py	2026-10-17 16:45:19.463582321 -0400
+++ fixed.py	2026-10-17 16:45:19.675588143 -0400
@@ -1,6 +1,6 @@
 from typing import TypeAlias
 from pathlib import Path
-P: TypeAlias = "Path"
+P: TypeAlias = Path
 p: P = Path('.')
 print(p.exists())
 print(p.is_absolute())
True
False
r1-p005 · String Concatenation Inside Quotes Left Unchanged
1from typing import TypeAlias
2BadAlias: TypeAlias = "int" "|" "None"
3print(type(BadAlias))
4print(repr(BadAlias))
--- orig.py	2026-10-17 16:45:19.800591576 -0400
+++ fixed.py	2026-10-17 16:45:20.001597096 -0400
@@ -1,4 +1,4 @@
 from typing import TypeAlias
-BadAlias: TypeAlias = "int" "|" "None"
+BadAlias: TypeAlias = int|None
 print(type(BadAlias))
 print(repr(BadAlias))
<class 'str'>
'int|None'
r1-p006 · Tool Expecting Quotes for Metadata Inspection
1from typing import TypeAlias
2DocAlias: TypeAlias = "str | None" # Tool expects this format
3source = open(__file__).read()
4if '"DocAlias:' in source and '="' in source:
5 print('Tool would find it')
6else:
7 print('Tool misses it')
--- orig.py	2026-10-17 16:45:20.115600222 -0400
+++ fixed.py	2026-10-17 16:45:20.294605132 -0400
@@ -1,5 +1,5 @@
 from typing import TypeAlias
-DocAlias: TypeAlias = "str | None"  # Tool expects this format
+DocAlias: TypeAlias = str | None  # Tool expects this format
 source = open(__file__).read()
 if '"DocAlias:' in source and '="' in source:
     print('Tool would find it')
Tool would find it
r1-p007 · String Formatting Edge Cases: % , format(), f-strings
1from typing import TypeAlias
2ListInt: TypeAlias = "list[int]"
3s = f"{ListInt}"
4print(s)
5try:
6 eval(s)
7except Exception as e:
8 print(type(e).__name__, e)
list[int]
r1-p008 · Evaluation Order & Side Effects in Merged Expressions
1from typing import TypeAlias
2def get_type():
3 print('Side effect')
4 return 'int'
5SideAlias: TypeAlias = f"{get_type()} | None"
6print('Before use')
7x: SideAlias = 5
8print('After use')
Side effect
Before use
After use