ruff RUF106
labelled unknown
Analysis Nemotron 3 Super
Flags Ruff-specific suppression comments using numeric rule codes instead of human-readable rule names.
Fix: Replaces numeric rule codes in Ruff suppression comments with their corresponding human-readable rule names (e.g., F401 → unused-import), preserving comment structure, spacing, and non-numeric content.
12 hazards
- Rewriting ignore[F401] to ignore[unused-import] assumes the mapping is correct; if Ruff’s internal rule name for F401 changes or differs in a plugin, the fix may apply an incorrect or nonexistent rule name.
- If a comment contains a code like 999 that is not a valid Ruff rule, replacing it with a fabricated name (e.g., ignore[999] → ignore[unknown]) could produce an invalid suppression that Ruff ignores or misinterprets.
- In a disable comment like ruff: disable[F401,F841], rewriting to named rules could fail if one code maps to a name that Ruff does not recognize as a suppressible rule (e.g., a reporting-only rule), potentially leaving violations unsuppressed.
- The fix does not preserve inline comments after the suppression (e.g., # ruff: ignore[F401] # temporary) because it may discard trailing text when reconstructing the comment, dropping meaningful annotations.
- If the suppression comment contains non-ASCII characters or unusual whitespace (e.g., # ruff: ignore[F401 ]), the fix might normalize or drop them during parsing/reconstruction, altering the comment’s appearance or encoding.
- In a multiline string or docstring that resembles a suppression comment (e.g., """ # ruff: ignore[F401] """), the tool might incorrectly apply the fix inside the string, corrupting the literal content.
- If the code uses a custom Ruff plugin that assigns F401 to a non-standard rule (e.g., a project-specific lint), replacing F401 with 'unused-import' would suppress the wrong rule or fail to suppress the intended one.
- The fix may interfere with source control or review tools if it changes comments in a way that obscures the original intent (e.g., replacing a ticket number-associated code like F401#[fix:123] with a generic name).
- In a file with mixed tabs and spaces in comments, the rewrite might alter indentation within the comment line, potentially violating whitespace policies even though comments are usually exempt.
- If the suppression comment is part of a larger comment block processed by a documentation tool (e.g., Sphinx), changing rule codes to names could break parsing if the tool expects numeric codes for cross-referencing.
- The fix does not account for conditional suppression via environment variables or pragmas embedded in the comment (e.g., # ruff: ignore[F401] if DEBUG), and rewriting could break such logic if the tool strips or reorders conditional syntax.
- If the same numeric code appears multiple times in a comment (e.g., ignore[F401,F401]), the deduplication or reordering during fix application could alter the suppression semantics if order or repetition were significant (though Ruff treats them as a set).
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | silent prediction off | Invalid rule code replacement produces unknown suppression | If a comment contains a code like 999 that is not a valid Ruff rule, replacing it with a fabricated name (e.g., ignore[999] → ignore[unknown]) could produce an invalid suppression that Ruff ignores or |
| r1-p002 | fix ok | Evaluation order and side effects in tuple assignment with ignored expression | Evaluation order and side effects when expressions are merged, duplicated or deleted |
| r1-p003 | fix ok | Mixed whitespace in comment preserved but visual alignment misleading | In a file with mixed tabs and spaces in comments, the rewrite might alter indentation within the comment line, potentially violating whitespace policies even though comments are usually exempt. |
| r1-p004 | fix ok | Dict with function values affected by ignored variable | dict ordering, duplicate keys, __hash__/__eq__ overrides, sets |
| r1-p005 | fix ok | Star-import side effect depends on ignored flag | star-imports, module-level side effects, __all__ |
| r1-p006 | fix ok | Docstring attached to function whose body has ignored var | comments and docstrings attached to the removed or moved code |
| r1-p007 | fix ok | Trailing inline comment discarded during suppression rewrite | The fix does not preserve inline comments after the suppression (e.g., # ruff: ignore[F401] # temporary) because it may discard trailing text when reconstructing the comment, dropping meaningful anno |
| r1-p008 | fix ok | Sphinx-like comment block broken by numeric-to-name change in suppressions | If the suppression comment is part of a larger comment block processed by a documentation tool (e.g., Sphinx), changing rule codes to names could break parsing if the tool expects numeric codes for cr |
| r2-p001 | fix ok | Disable comment with potential invalid rule name after rewrite | Rewriting numeric codes to names could produce unrecognized rule names (e.g., reporting-only rules), leaving violations unsuppressed. |
| r2-p002 | fix ok | Conditional suppression broken by rewrite | Fix does not preserve conditional syntax like 'if DEBUG' in suppression comments, breaking logic-dependent suppression. |
| r2-p003 | silent prediction off | Incorrect rule name mapping due to plugin or version mismatch | Fix assumes static mapping; if plugin changes F401 meaning, rewrite applies wrong suppression. |
| r2-p004 | fix ok | Non-ASCII whitespace in suppression comment | Fix might normalize or drop non-ASCII or unusual whitespace (e.g., NBSP) during parsing/reconstruction, altering comment appearance or encoding. |
Sources
r1-p001 · Invalid rule code replacement produces unknown suppression
1x = []
2# Simulate conditional execution based on whether suppression works
3for i in range(2):
4 if i == 0:
5 # Import that should trigger F401 if not suppressed
6 import sys # ruff: ignore[999]
7 x.append('imported')
8 else:
9 x.append('rechecked')
10print(len(x))
2
r1-p002 · Evaluation order and side effects in tuple assignment with ignored expression
1def f():
2 print('side', end='')
3 return 1
4# Side effect in ignored expression: function call with print
5a, b = f(), 2 # ruff: ignore[F841]
6print(a, b)
--- orig.py 2026-10-17 17:51:25.773306553 -0400 +++ fixed.py 2026-10-17 17:51:25.925327512 -0400 @@ -2,5 +2,5 @@ print('side', end='') return 1 # Side effect in ignored expression: function call with print -a, b = f(), 2 # ruff: ignore[F841] +a, b = f(), 2 # ruff: ignore[unused-variable] print(a, b)
side1 2
r1-p003 · Mixed whitespace in comment preserved but visual alignment misleading
1# Configuration with mixed whitespace # ruff: ignore[W291]
2value = 42
3# After rewrite, comment still has \t but linters may warn
4print(value)
--- orig.py 2026-10-17 17:51:26.020340608 -0400 +++ fixed.py 2026-10-17 17:51:26.159359747 -0400 @@ -1,4 +1,4 @@ -# Configuration with mixed whitespace # ruff: ignore[W291] +# Configuration with mixed whitespace # ruff: ignore[trailing-whitespace] value = 42 # After rewrite, comment still has \t but linters may warn print(value)
42
r1-p004 · Dict with function values affected by ignored variable
1def get_key():
2 return 'dynamic'
3# Ignored variable used in dict construction
4tmp = get_key() # ruff: ignore[F841]
5d = {tmp: 'value', 'static': 1}
6print(d.get('dynamic', 'missing'))
--- orig.py 2026-10-17 17:51:26.255372965 -0400 +++ fixed.py 2026-10-17 17:51:26.417395270 -0400 @@ -1,6 +1,6 @@ def get_key(): return 'dynamic' # Ignored variable used in dict construction -tmp = get_key() # ruff: ignore[F841] +tmp = get_key() # ruff: ignore[unused-variable] d = {tmp: 'value', 'static': 1} print(d.get('dynamic', 'missing'))
value
r1-p005 · Star-import side effect depends on ignored flag
1__all__ = ['CONDITION']
2CONDITION = False
3if CONDITION:
4 from os import * # ruff: ignore[F403]
5 # If not suppressed, F403 triggers; side effect is polluting namespace
6print('CONDITION' in globals())
--- orig.py 2026-10-17 17:51:26.516408902 -0400 +++ fixed.py 2026-10-17 17:51:26.681431620 -0400 @@ -1,6 +1,6 @@ __all__ = ['CONDITION'] CONDITION = False if CONDITION: - from os import * # ruff: ignore[F403] + from os import * # ruff: ignore[undefined-local-with-import-star] # If not suppressed, F403 triggers; side effect is polluting namespace print('CONDITION' in globals())
True
r1-p006 · Docstring attached to function whose body has ignored var
1def process():
2 """Process data if flag is set."""
3 flag = True # ruff: ignore[F841]
4 if flag:
5 return 'ok'
6 return 'fail'
7print(process())
--- orig.py 2026-10-17 17:51:26.780445251 -0400 +++ fixed.py 2026-10-17 17:51:26.936466731 -0400 @@ -1,6 +1,6 @@ def process(): """Process data if flag is set.""" - flag = True # ruff: ignore[F841] + flag = True # ruff: ignore[unused-variable] if flag: return 'ok' return 'fail'
ok
r1-p007 · Trailing inline comment discarded during suppression rewrite
1threshold = 10 # ruff: ignore[F841] # temporarily ignore while debugging
2value = 5
3if value > threshold:
4 print('high')
5else:
6 print('low') # Expected: 'low'
--- orig.py 2026-10-17 17:51:27.036480492 -0400 +++ fixed.py 2026-10-17 17:51:27.197502627 -0400 @@ -1,4 +1,4 @@ -threshold = 10 # ruff: ignore[F841] # temporarily ignore while debugging +threshold = 10 # ruff: ignore[unused-variable] # temporarily ignore while debugging value = 5 if value > threshold: print('high')
low
r1-p008 · Sphinx-like comment block broken by numeric-to-name change in suppressions
1##
2# This section covers error handling (see RFC 999)
3# ruff: ignore[E501] # Line too long in doc example
4# See also: @ref error-handling
5value = 'error'
6print('loaded' if value else 'failed')
--- orig.py 2026-10-17 17:51:27.296516238 -0400 +++ fixed.py 2026-10-17 17:51:27.473540573 -0400 @@ -1,6 +1,6 @@ ## # This section covers error handling (see RFC 999) -# ruff: ignore[E501] # Line too long in doc example +# ruff: ignore[line-too-long] # Line too long in doc example # See also: @ref error-handling value = 'error' print('loaded' if value else 'failed')
loaded
r2-p001 · Disable comment with potential invalid rule name after rewrite
1import sys
2# ruff: disable[F403]
3from star import *
4print('star imported')
5# This line should trigger F403 if suppression fails
6if False:
7 from star import wildcard # noqa: F403
--- orig.py 2026-10-17 17:52:22.068753513 -0400 +++ fixed.py 2026-10-17 17:52:22.456802745 -0400 @@ -1,5 +1,5 @@ import sys -# ruff: disable[F403] +# ruff: disable[undefined-local-with-import-star] from star import * print('star imported') # This line should trigger F403 if suppression fails
r2-p002 · Conditional suppression broken by rewrite
1DEBUG = True
2# ruff: ignore[F401] if DEBUG
3import os # This should be ignored only if DEBUG is True
4if not DEBUG:
5 print(os.path) # This line should cause F401 if suppression failed
6else:
7 print('suppression active')
--- orig.py 2026-10-17 17:52:22.666829391 -0400 +++ fixed.py 2026-10-17 17:52:22.836850961 -0400 @@ -1,5 +1,5 @@ DEBUG = True -# ruff: ignore[F401] if DEBUG +# ruff: ignore[unused-import] if DEBUG import os # This should be ignored only if DEBUG is True if not DEBUG: print(os.path) # This line should cause F401 if suppression failed
suppression active
r2-p003 · Incorrect rule name mapping due to plugin or version mismatch
1import ast
2import re
3with open(__file__, 'r') as f:
4 lines = f.readlines()
5target_line = None
6for i, line in enumerate(lines):
7 if '# ruff: ignore[F401]' in line:
8 target_line = i
9 break
10if target_line is None:
11 print('suppression comment not found')
12 exit(1)
13comment = lines[target_line]
14# Check if the comment has been rewritten to a name that is not the expected one for our intent
15# We intended to suppress a hypothetical rule 'custom-rule', but we used F401.
16# The fix will change it to 'unused-import'.
17# If the fix produces a string that is not 'unused-import', we consider it incorrect for our intent.
18# We look for the pattern ignore[...] and extract the content.
19match = re.search(r'ignore\[([^]]+)\]', comment)
20if not match:
21 print('no ignore found')
22 exit(1)
23content = match.group(1)
24# We expected the fix to produce 'unused-import' for F401
25# If it produces something else, it's wrong for our goal (even if it's a valid rule)
26if content == 'unused-import':
27 print('suppression rewritten correctly for intent')
28 print(42)
29else:
30 print(f'suppression rewritten to unexpected content: {content}')
31 print(0)
suppression rewritten to unexpected content: F401 0
r2-p004 · Non-ASCII whitespace in suppression comment
1msg = 'start'
2# ruff: ignore[F401 ] # Note: \u00A0 is NO-BREAK SPACE after F401
3if msg:
4 print(msg)
5# After fix, if NBSP is stripped, the comment becomes '# ruff: ignore[F401]'
6# We detect if the NBSP is preserved by checking the raw byte representation of the comment.
7# We print a trace that depends on whether the NBSP is still present.
--- orig.py 2026-10-17 17:52:23.083882287 -0400 +++ fixed.py 2026-10-17 17:52:23.240902179 -0400 @@ -1,7 +1,7 @@ msg = 'start' -# ruff: ignore[F401 ] # Note: \u00A0 is NO-BREAK SPACE after F401 +# ruff: ignore[unused-import ] # Note: \u00A0 is NO-BREAK SPACE after F401 if msg: print(msg) -# After fix, if NBSP is stripped, the comment becomes '# ruff: ignore[F401]' +# After fix, if NBSP is stripped, the comment becomes '# ruff: ignore[unused-import]' # We detect if the NBSP is preserved by checking the raw byte representation of the comment. # We print a trace that depends on whether the NBSP is still present.
start