ruff RUF101
labelled unknown
Analysis Nemotron 3 Super
Flags 'noqa' directives using deprecated rule codes that have been redirected to canonical replacements.
Fix: Replaces each deprecated rule code in a noqa directive with its current canonical replacement (e.g., PGH001 → S307, S602 → S603, SIM103 → SIM115, RET503 → RET506, RET504 → RET506, RET506 → RET506, G001 → G004, ERA001 → ERA002).
12 hazards
- The rewrite may incorrectly merge multiple noqa codes if the original line contains a trailing comma after the deprecated code, altering suppression intent.
- If the noqa directive is split across multiple lines via backslash continuation, the rewrite may fail to match or corrupt the line structure.
- In a line with multiple noqa codes separated by spaces (not commas), the rewrite may not match due to unexpected delimiter handling.
- If the deprecated code appears as part of a larger identifier (e.g., in a string or comment), the rewrite could erroneously modify unrelated text.
- When the noqa directive is embedded within a multiline string or docstring, the rewrite may break string syntax or introduce invalid escape sequences.
- If the line contains a '#' character inside brackets or quotes (e.g., in a list or regex), the rewrite may mismatch the actual noqa directive due to incorrect comment detection.
- The rewrite may remove or reorder inline comments that appear after the noqa directive on the same line, changing documentation or intent.
- If the deprecated code is written with mixed case (e.g., 'pgh001'), the rewrite may not trigger due to case sensitivity, leaving the deprecated code unchanged.
- In files with non-UTF-8 encoding, the rewrite may corrupt byte sequences when modifying the source, leading to decode errors.
- If the noqa directive is the only content on a line and the rewrite changes its length, it may affect blank-line-dependent tools or formatters that rely on line count.
- When the line ends with whitespace after the noqa directive, the rewrite may preserve or drop that whitespace inconsistently across editor configurations.
- If the deprecated code is part of a larger noqa message (e.g., '# noqa: PGH001 some reason'), the rewrite may produce ambiguous or invalid code by replacing only the code portion.
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | fix ok | Class attribute descriptor interaction | class attributes vs instance attributes, descriptors, properties with side effects |
| r1-p002 | fix ok | Non-UTF-8 encoding corruption | In files with non-UTF-8 encoding, the rewrite may corrupt byte sequences when modifying the source, leading to decode errors. |
| r1-p003 | fix ok | Trailing whitespace preservation | When the line ends with whitespace after the noqa directive, the rewrite may preserve or drop that whitespace inconsistently across editor configurations. |
| r1-p004 | fix ok | Dict ordering and duplicate keys | dict ordering, duplicate keys, __hash__/__eq__ overrides, sets |
| r1-p005 | fix ok | Trailing comma merging noqa codes | The rewrite may incorrectly merge multiple noqa codes if the original line contains a trailing comma after the deprecated code, altering suppression intent. |
| r1-p006 | invalid | Walrus and late binding in closures | walrus, comprehensions scoping, late binding in closures and lambdas |
| r1-p007 | fix ok | Shadowed builtins and redefinition | shadowed builtins and names redefined later in the module |
| r1-p008 | fix ok | Exceptions in finally/else clauses | exceptions raised inside the rewritten code, finally/else clauses, exception chaining |
| r2-p001 | invalid | Deprecated code in string literal | If the deprecated code appears as part of a larger identifier (e.g., in a string or comment), the rewrite could erroneously modify unrelated text. |
| r2-p002 | fix ok | Inline comment after noqa | The rewrite may remove or reorder inline comments that appear after the noqa directive on the same line, changing documentation or intent. |
| r2-p003 | fix ok | Keyword-only and positional-only args | keyword-only, positional-only, *args/**kwargs forwarding, defaults evaluated once |
| r2-p004 | fix ok | Runtime type annotation evaluation | type annotations evaluated at runtime, typing-only imports |
| r2-p005 | fix ok | Float coercion and rounding | int/float/bool coercion, Decimal, division and rounding |
| r2-p006 | silent prediction off | Mutable default argument aliasing | mutable default arguments and aliasing after a rewrite |
| r2-p007 | silent prediction off | Hash inside brackets mistaken for comment | If the line contains a '#' character inside brackets or quotes (e.g., in a list or regex), the rewrite may mismatch the actual noqa directive due to incorrect comment detection. |
| r2-p008 | fix ok | Bytes vs str encoding | bytes vs str, encoding and newline handling, text vs binary modes |
Sources
r1-p001 · Class attribute descriptor interaction
1class C:
2 x = eval('1') # noqa: PGH001
3 def __init__(self):
4 self.y = self.x + 1
5c = C()
6print(c.y)
--- orig.py 2026-10-17 17:50:01.328899933 -0400 +++ fixed.py 2026-10-17 17:50:01.617945167 -0400 @@ -1,5 +1,5 @@ class C: - x = eval('1') # noqa: PGH001 + x = eval('1') # noqa: S307 def __init__(self): self.y = self.x + 1 c = C()
2
r1-p002 · Non-UTF-8 encoding corruption
1# -*- coding: latin-1 -*-
2x = eval('\xe9') # noqa: PGH001
3print(x)
--- orig.py 2026-10-17 17:50:01.722961602 -0400 +++ fixed.py 2026-10-17 17:50:02.109021993 -0400 @@ -1,3 +1,3 @@ # -*- coding: latin-1 -*- -x = eval('\xe9') # noqa: PGH001 +x = eval('\xe9') # noqa: S307 print(x)
r1-p003 · Trailing whitespace preservation
1x = eval('2') # noqa: PGH001
2print(x)
--- orig.py 2026-10-17 17:50:02.315054187 -0400 +++ fixed.py 2026-10-17 17:50:02.481080130 -0400 @@ -1,2 +1,2 @@ -x = eval('2') # noqa: PGH001 +x = eval('2') # noqa: S307 print(x)
2
r1-p004 · Dict ordering and duplicate keys
1d = {}
2d[eval('1')] = 'a' # noqa: PGH001
3d[eval('1')] = 'b'
4print(d)
--- orig.py 2026-10-17 17:50:02.580095602 -0400 +++ fixed.py 2026-10-17 17:50:02.743121075 -0400 @@ -1,4 +1,4 @@ d = {} -d[eval('1')] = 'a' # noqa: PGH001 +d[eval('1')] = 'a' # noqa: S307 d[eval('1')] = 'b' print(d)
{1: 'b'}r1-p005 · Trailing comma merging noqa codes
1x = eval('3'), # noqa: PGH001,
2print(x[0])
--- orig.py 2026-10-17 17:50:02.843136703 -0400 +++ fixed.py 2026-10-17 17:50:03.005162020 -0400 @@ -1,2 +1,2 @@ -x = eval('3'), # noqa: PGH001, +x = eval('3'), # noqa: S307, print(x[0])
3
r1-p006 · Walrus and late binding in closures (generated program does not parse: Traceback (most recent call last):)
1fs = []
2for i in range(2):
3 if (x := eval(str(i))) # noqa: PGH001
4 fs.append(lambda: x)
5print([f() for f in fs])
r1-p007 · Shadowed builtins and redefinition
1eval = lambda s: 99
2x = eval('1') # noqa: PGH001
3print(x)
4eval = __builtins__.eval
5print(eval('2'))
--- orig.py 2026-10-17 17:50:03.236198066 -0400 +++ fixed.py 2026-10-17 17:50:03.396223032 -0400 @@ -1,5 +1,5 @@ eval = lambda s: 99 -x = eval('1') # noqa: PGH001 +x = eval('1') # noqa: S307 print(x) eval = __builtins__.eval print(eval('2'))
99 2
r1-p008 · Exceptions in finally/else clauses
1try:
2 x = eval('1/0') # noqa: PGH001
3except ZeroDivisionError as e:
4 print('caught:', e)
5else:
6 print('no error')
7finally:
8 print('finally')
--- orig.py 2026-10-17 17:50:03.502239572 -0400 +++ fixed.py 2026-10-17 17:50:03.656263603 -0400 @@ -1,5 +1,5 @@ try: - x = eval('1/0') # noqa: PGH001 + x = eval('1/0') # noqa: S307 except ZeroDivisionError as e: print('caught:', e) else:
caught: division by zero finally
r2-p001 · Deprecated code in string literal (generated program does not parse: Traceback (most recent call last):)
1import sys
2# Test: does rewrite touch 'PGH001' inside a string?
3s = '\\'eval(cmd)\\' # noqa: PGH001
4print(repr(s))
5if s == "'eval(cmd)'":
6 print('PASS: string unchanged')
7else:
8 print('FAIL: string altered:', repr(s))
r2-p002 · Inline comment after noqa
1# Check if trailing comment survives rewrite
2result = eval('1+1') # noqa: PGH001 # this comment explains why we allow eval
3print(result)
4print('# this comment explains why we allow eval' in open(__file__).readlines()[1])
--- orig.py 2026-10-17 17:50:08.350993254 -0400 +++ fixed.py 2026-10-17 17:50:08.510017876 -0400 @@ -1,4 +1,4 @@ # Check if trailing comment survives rewrite -result = eval('1+1') # noqa: PGH001 # this comment explains why we allow eval +result = eval('1+1') # noqa: S307 # this comment explains why we allow eval print(result) print('# this comment explains why we allow eval' in open(__file__).readlines()[1])
2 True
r2-p003 · Keyword-only and positional-only args
1def f(a, /, b, *, c=eval('1')): # noqa: PGH001
2 return a + b + c
3print(f(10, 20))
4try:
5 f(10, b=20)
6except TypeError as e:
7 print('Expected:', e)
--- orig.py 2026-10-17 17:50:08.611033515 -0400 +++ fixed.py 2026-10-17 17:50:08.774058756 -0400 @@ -1,4 +1,4 @@ -def f(a, /, b, *, c=eval('1')): # noqa: PGH001 +def f(a, /, b, *, c=eval('1')): # noqa: S307 return a + b + c print(f(10, 20)) try:
31
r2-p004 · Runtime type annotation evaluation
1T = eval('int') # noqa: PGH001
2def g(x: T) -> T:
3 return x + 1
4print(g(5))
5print(T)
--- orig.py 2026-10-17 17:50:08.876074550 -0400 +++ fixed.py 2026-10-17 17:50:09.038099627 -0400 @@ -1,4 +1,4 @@ -T = eval('int') # noqa: PGH001 +T = eval('int') # noqa: S307 def g(x: T) -> T: return x + 1 print(g(5))
6 <class 'int'>
r2-p005 · Float coercion and rounding
1from decimal import Decimal
2x = Decimal(eval('10')) / Decimal('3') # noqa: PGH001
3print(round(x, 2))
4print(float(x))
5print(bool(x))
--- orig.py 2026-10-17 17:50:09.142115707 -0400 +++ fixed.py 2026-10-17 17:50:09.308141373 -0400 @@ -1,5 +1,5 @@ from decimal import Decimal -x = Decimal(eval('10')) / Decimal('3') # noqa: PGH001 +x = Decimal(eval('10')) / Decimal('3') # noqa: S307 print(round(x, 2)) print(float(x)) print(bool(x))
3.33 3.3333333333333335 True
r2-p006 · Mutable default argument aliasing
1def append_val(val, lst=[]): # noqa: RET503
2 lst.append(val)
3 return lst
4print(append_val(1))
5print(append_val(2))
6print(append_val(3))
[1] [1, 2] [1, 2, 3]
r2-p007 · Hash inside brackets mistaken for comment
1import re
2pattern = ['a#b', 'c#d'] # noqa: SIM103
3match = re.search(r'#', str(pattern))
4print('Found #' in str(pattern) if match else 'No # found')
5print(pattern)
False ['a#b', 'c#d']
r2-p008 · Bytes vs str encoding
1data = eval('"hello"').encode() # noqa: PGH001
2with open('test.bin', 'wb') as f:
3 f.write(data)
4with open('test.bin', 'rb') as f:
5 read = f.read()
6print(read == b'hello')
7import os
8os.remove('test.bin')
--- orig.py 2026-10-17 17:50:09.683199352 -0400 +++ fixed.py 2026-10-17 17:50:09.841223781 -0400 @@ -1,4 +1,4 @@ -data = eval('"hello"').encode() # noqa: PGH001 +data = eval('"hello"').encode() # noqa: S307 with open('test.bin', 'wb') as f: f.write(data) with open('test.bin', 'rb') as f:
True