ruff RUF102
labelled unknown
Analysis Nemotron 3 Super
Flags invalid `noqa` rule codes in inline comments.
Fix: Removes the entire inline `# noqa: <code>` comment if all codes are invalid; otherwise, removes only the invalid codes from the comment, preserving valid ones and the comment if any valid codes remain.
12 hazards
- Removing a trailing `# noqa` comment could change the interpretation of preceding tokens if the comment was acting as a line continuation via backslash (though rare in Python).
- If the `# noqa` comment contains manual spacing or alignment that affects readability or tooling, removing it alters whitespace-sensitive processing.
- In a line like `x = 1 # noqa: ABC123 # another comment`, removing the invalid code may leave `# # another comment` which is syntactically odd but semantically preserved; however, if the fix improperly handles spacing, it could collapse comments incorrectly.
- If the line has a `# noqa:` comment with invalid codes and the fix removes the entire comment, any dependent tooling that parses `# noqa` for metadata (even with invalid codes) may lose expected behavior.
- When the fix removes only part of a `# noqa: code1,code2` comment and leaves a trailing comma (e.g., `# noqa: VALID,`), the resulting comment may be misparsed by tools expecting clean lists.
- If the line contains a `#` inside a string literal (e.g., `s = "x # noqa: FAKE"`), the rule should not fire, but if it did due to a bug, removing the comment-like text would corrupt the string.
- If the `# noqa` comment is the only content after code and its removal leaves trailing whitespace, it is semantically neutral but may affect diff tools or formatting expectations.
- In rare cases where a `# noqa` comment is used to intentionally disable a linter for the next line via some non-standard tool, removing it could re-enable checking incorrectly.
- If the code line ends with a `# noqa` comment and the fix removes it, and the line previously relied on the comment to avoid trailing whitespace warnings in some editors, removal could reintroduce such warnings (though this is editor-specific, not semantic).
- When the fix preserves the `# noqa` comment with only valid codes, if the original comment had irregular spacing (e.g., `# noqa: E402`), normalization might alter formatting but not semantics.
- If the line has multiple `#` comments (e.g., `x = 1 # first # noqa: FAKE`), and the fix removes only the `# noqa` part, the remaining comment structure changes but does not affect execution.
- If the `# noqa` comment includes a code that is invalid for Ruff but valid for another tool (e.g., `mypy`), and the user relies on Ruff not stripping it due to `lint.external` configuration, the fix would still remove it unless configured otherwise, breaking cross-tool suppression.
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | silent prediction off | class attributes vs instance attributes | Removing a spurious noqa comment on a class attribute assignment changes which descriptor __set__ method runs, altering state shared via class vs instance. |
| r1-p002 | silent prediction off | dict ordering duplicate keys | Removing a spurious noqa comment on a dict literal with duplicate keys changes which value survives, altering iteration order and final state. |
| r1-p003 | silent | # inside string literal | If the rule incorrectly fires on a # inside a string, removing it would corrupt the string value, changing program output. |
| r1-p004 | silent prediction off | intentional next-line disable | A non-standard tool uses # noqa to suppress warnings on the *next* line; removing it re-enables checking and alters behavior via side effects. |
| r1-p005 | invalid | pathlib vs os.path | Removing a spurious noqa comment on a path assignment changes which library interprets the path, altering symlink resolution behavior. |
| r1-p006 | silent prediction off | irregular spacing preservation | When preserving valid codes, irregular spacing in the original comment is lost, changing whitespace but not semantics; we detect via comment inspection. |
| r1-p007 | silent prediction off | star-imports module side effects | Removing a spurious noqa comment on an import changes whether a module-level side effect (like a register) runs, altering available names after star-import. |
| r1-p008 | silent prediction off | file modes truncation partial writes | Removing a spurious noqa comment on a file open changes mode interpretation, causing truncation vs append and altering final file content. |
| r2-p001 | fix ok | String formatting edge case with % operator | string formatting edge cases: %, format, f-strings, repr vs str, nested quotes |
| r2-p002 | fix ok | Mutable default argument and aliasing | mutable default arguments and aliasing after a rewrite |
| r2-p003 | fix ok | Trailing comment spacing preservation | In a line like `x = 1 # noqa: ABC123 # another comment`, removing the invalid code may leave `# # another comment` which is syntactically odd but semantically preserved; however, if the fix imprope |
| r2-p004 | fix ok | Whitespace-sensitive comment alignment | If the `# noqa` comment contains manual spacing or alignment that affects readability or tooling, removing it alters whitespace-sensitive processing. |
| r2-p005 | silent prediction off | Keyword-only and positional-only arguments | keyword-only, positional-only, *args/**kwargs forwarding, defaults evaluated once |
| r2-p006 | silent prediction off | Dependent tooling parsing invalid noqa | If the line has a `# noqa:` comment with invalid codes and the fix removes the entire comment, any dependent tooling that parses `# noqa` for metadata (even with invalid codes) may lose expected behav |
| r2-p007 | silent prediction off | Binary file mode handling | bytes vs str, encoding and newline handling, text vs binary modes |
| r2-p008 | silent prediction off | Non-file context manager with write() | context managers that are not files, objects with write() but no close() |
Sources
r1-p001 · class attributes vs instance attributes
1class A:
2 x = 1 # noqa: FAKE
3
4def test():
5 a = A()
6 print(a.x, hasattr(A, 'x'))
7 a.x = 2
8 print(a.x, A.x)
9
10test()
1 True 2 1
r1-p002 · dict ordering duplicate keys
1d = {
2 'a': 1,
3 'b': 2,
4 'a': 3 # noqa: FAKE
5}
6print(list(d.items()))
[('a', 3), ('b', 2)]r1-p003 · # inside string literal
1s = "x # noqa: FAKE"
2print(repr(s))
'x # noqa: FAKE'
r1-p004 · intentional next-line disable
1flag = 0 # noqa: FAKE
2if flag: # this line would be checked if tool behaved strangely
3 print('unreachable')
4else:
5 print(flag)
0
r1-p005 · pathlib vs os.path (generated program is not deterministic)
1import os
2from pathlib import Path
3p = 'tmp' # noqa: FAKE
4os.mkdir(p)
5os.symlink('tmp/target', p + '/link')
6print(Path(p + '/link').resolve() == Path(os.path.realpath(p + '/link')))
r1-p006 · irregular spacing preservation
1import ast
2code = 'x = 1 # noqa: E402'
3tree = ast.parse(code)
4comment = tree.body[0].value.comment if hasattr(tree.body[0].value, 'comment') else None
5print(comment is None or 'E402' in str(comment))
True
r1-p007 · star-imports module side effects
1REGISTERED = []
2def register(name):
3 REGISTERED.append(name)
4register('mod') # noqa: FAKE
5from mod import *
6print('mod' in REGISTERED)
r1-p008 · file modes truncation partial writes
1with open('test.txt', 'w') as f:
2 f.write('hello') # noqa: FAKE
3with open('test.txt', 'r') as f:
4 print(f.read())
hello
r2-p001 · String formatting edge case with % operator
1name = 'world'
2greeting = 'Hello %s' % name # noqa: ABC123
3print(greeting)
--- orig.py 2026-10-17 17:50:39.992777017 -0400 +++ fixed.py 2026-10-17 17:50:40.164802388 -0400 @@ -1,3 +1,3 @@ name = 'world' -greeting = 'Hello %s' % name # noqa: ABC123 +greeting = 'Hello %s' % name print(greeting)
Hello world
r2-p002 · Mutable default argument and aliasing
1def f(x=[]): # noqa: ZZZ999
2 x.append(1)
3 return x
4print(f())
5print(f())
--- orig.py 2026-10-17 17:50:40.259816399 -0400 +++ fixed.py 2026-10-17 17:50:40.423840588 -0400 @@ -1,4 +1,4 @@ -def f(x=[]): # noqa: ZZZ999 +def f(x=[]): x.append(1) return x print(f())
[1] [1, 1]
r2-p003 · Trailing comment spacing preservation
1x = 1 # noqa: ABC123 # keep this
2print(x)
--- orig.py 2026-10-17 17:50:40.518854599 -0400 +++ fixed.py 2026-10-17 17:50:40.683878935 -0400 @@ -1,2 +1,2 @@ -x = 1 # noqa: ABC123 # keep this +x = 1 # keep this print(x)
1
r2-p004 · Whitespace-sensitive comment alignment
1x = 1 # noqa: FAKE001
2print(x)
--- orig.py 2026-10-17 17:50:40.778892947 -0400 +++ fixed.py 2026-10-17 17:50:40.945917578 -0400 @@ -1,2 +1,2 @@ -x = 1 # noqa: FAKE001 +x = 1 print(x)
1
r2-p005 · Keyword-only and positional-only arguments
1def f(a, /, b, *, c=[]): # noqa: INVALID
2 c.append(1)
3 return a, b, c
4print(f(1, 2, c=3))
5print(f(1, 2, c=4))
r2-p006 · Dependent tooling parsing invalid noqa
1config = 42 # noqa: NOT_A_RULE # tool-expects:this
2print(config)
42
r2-p007 · Binary file mode handling
1with open('test.bin', 'wb') as f: # noqa: BADCODE
2 f.write(b'hello')
3with open('test.bin', 'rb') as f:
4 print(f.read())
5import os
6os.remove('test.bin')
b'hello'
r2-p008 · Non-file context manager with write()
1import io
2buf = io.StringIO()
3with buf as f: # noqa: UNKNOWN
4 f.write('test')
5print(buf.getvalue())