fixhunt

ruff RUF031

labelled unknown
Runs / 2026-10-17T21-44-14-335Z-t2o0-ruff-RUF031ruff 0.17.12026-10-17 21:44 UTC8 programs × 2 round(s)16 programs, 8 fired, 8 fixed, 0 findings, 0 rejectedmodel cost $0.0031

Analysis Nemotron 3 Super

Flags non-empty tuple literals used as subscription indices when parentheses are present but disallowed by configuration.

Fix: Removes the outer parentheses around the tuple literal inside the subscription brackets, preserving inner elements and formatting exactly as written.

10 hazards
  • Rewriting `(expr,)` as `expr,` changes a parenthesized expression into a tuple, altering meaning when `expr` is not a tuple-forming construct.
  • If the tuple contains a starred expression like `*(xs,)`, removing parentheses may invalidate syntax or change unpacking behavior.
  • In delayed evaluation contexts (e.g., lambdas or comprehensions inside the subscript), stripping parentheses could bind commas differently, altering structure.
  • If the tuple appears in an annotation-like context not recognized by Ruff’s typing heuristic (e.g., string annotations or conditional imports), the fix may be applied inappropriately.
  • When the tuple is part of a larger expression due to line continuation (e.g., backslash), removing parentheses may break syntactic grouping.
  • If the tuple contains a walrus operator (`:=`), removing parentheses may change the scope or binding behavior of the assigned variable.
  • Comments inside the parentheses (e.g., `(# x , 1)`) may be lost or misplaced if the rewrite does not preserve comment attachment.
  • In nested subscriptions like `d[(1, 2)][(3, 4)]`, fixing only the outer tuple may produce invalid or misleading intermediate expressions if inner tuples are also problematic.
  • If the subscript is part of a slice object construction via `__getitem__`, altering the tuple form may change how the slice is interpreted by the object’s implementation.
  • When the tuple is generated via a macro, decorator, or codegen tool that relies on the parentheses for parsing, removal may break tooling even if runtime behavior is preserved.

Programs

idresulttitlehazard
r1-p001fix okString Formatting Edge Case with Parentheses Removalstring formatting edge cases: %, format, f-strings, repr vs str, nested quotes
r1-p002fix okComment Preservation Hazardcomments and docstrings attached to the removed or moved code
r1-p003silent prediction offWalrus Operator Scope ChangeIf the tuple contains a walrus operator (`:=`), removing parentheses may change the scope or binding behavior of the assigned variable.
r1-p004fix okContext Manager Without Close()context managers that are not files, objects with write() but no close()
r1-p005silentPathlib vs os.path Behavior on Pathspathlib vs os.path behavior on relative paths, symlinks, missing files, bytes paths
r1-p006fix ok prediction offRuntime Type Annotation Evaluationtype annotations evaluated at runtime, typing-only imports
r1-p007fix okCustom Truthiness and Identity Checkstruthiness of custom __bool__/__len__, None vs falsy, 'is' vs '=='
r1-p008silent prediction offWalrus in Comprehension Late Bindingwalrus, comprehensions scoping, late binding in closures and lambdas
r2-p001silent prediction offKeyword-only and positional-only argument forwardingkeyword-only, positional-only, *args/**kwargs forwarding, defaults evaluated once
r2-p002silent prediction offWalrus operator scope changeIf the tuple contains a walrus operator (`:=`), removing parentheses may change the scope or binding behavior of the assigned variable.
r2-p003silent prediction offParenthesized expression vs tuple formationRewriting `(expr,)` as `expr,` changes a parenthesized expression into a tuple, altering meaning when `expr` is not a tuple-forming construct.
r2-p004fix okLine continuation grouping hazardWhen the tuple is part of a larger expression due to line continuation (e.g., backslash), removing parentheses may break syntactic grouping.
r2-p005fix okGenerator consumption differencegenerators vs lists, iterators consumed once, lazy vs eager evaluation
r2-p006fix okSlice object interpretation in __getitem__If the subscript is part of a slice object construction via `__getitem__`, altering the tuple form may change how the slice is interpreted by the object’s implementation.
r2-p007silent prediction offContext manager without close()context managers that are not files, objects with write() but no close()
r2-p008silent prediction offComment preservation hazardcomments and docstrings attached to the removed or moved code

Sources

r1-p001 · String Formatting Edge Case with Parentheses Removal
1x = [(1, 2)]
2print(str(x[(1, 2)]))
--- orig.py	2026-10-17 17:44:23.691356993 -0400
+++ fixed.py	2026-10-17 17:44:24.089354310 -0400
@@ -1,2 +1,2 @@
 x = [(1, 2)]
-print(str(x[(1, 2)]))
+print(str(x[1, 2]))
r1-p002 · Comment Preservation Hazard
1# comment before
2x = [10, 20]
3# important comment here
4val = x[(1, # inline comment
5 2)] # trailing
6print(val)
--- orig.py	2026-10-17 17:44:24.316352781 -0400
+++ fixed.py	2026-10-17 17:44:24.693350240 -0400
@@ -1,6 +1,6 @@
 # comment before
 x = [10, 20]
 # important comment here
-val = x[(1,  # inline comment
-              2)]  # trailing
+val = x[1,  # inline comment
+              2]  # trailing
 print(val)
r1-p003 · Walrus Operator Scope Change
1def f():
2 x = []
3 if (x := [(1, 2)])[0]:
4 pass
5 return x
6print(f())
[(1, 2)]
r1-p004 · Context Manager Without Close()
1class Writer:
2 def __enter__(self):
3 self.data = []
4 return self
5 def __exit__(self, *args):
6 pass
7 def write(self, v):
8 self.data.append(v)
9with Writer() as w:
10 w.write([(1, 2)] [(1, 2)])
11print(w.data[0][0])
--- orig.py	2026-10-17 17:44:25.030347970 -0400
+++ fixed.py	2026-10-17 17:44:25.412345397 -0400
@@ -7,5 +7,5 @@
     def write(self, v):
         self.data.append(v)
 with Writer() as w:
-    w.write([(1, 2)] [(1, 2)])
+    w.write([(1, 2)] [1, 2])
 print(w.data[0][0])
r1-p005 · Pathlib vs os.path Behavior on Paths
1import os
2import tempfile
3with tempfile.TemporaryDirectory() as d:
4 p = os.path.join(d, 'test.txt')
5 open(p, 'w').write('hello')
6 print(os.path.exists(p))
7 from pathlib import Path
8 print(Path(p).exists())
True
True
r1-p006 · Runtime Type Annotation Evaluation
1from typing import Tuple, List
2T: Tuple[int, int] = (1, 2)
3x = [T]
4print(type(x[(1, 2)]))
--- orig.py	2026-10-17 17:44:25.803342764 -0400
+++ fixed.py	2026-10-17 17:44:26.195340126 -0400
@@ -1,4 +1,4 @@
 from typing import Tuple, List
 T: Tuple[int, int] = (1, 2)
 x = [T]
-print(type(x[(1, 2)]))
+print(type(x[1, 2]))
r1-p007 · Custom Truthiness and Identity Checks
1class CustomBool:
2 def __init__(self, val):
3 self.val = val
4 def __bool__(self):
5 return self.val > 0
6 def __len__(self):
7 return 1 if self.val else 0
8x = [CustomBool(1), CustomBool(0)]
9print(bool(x[(1, 0)]))
--- orig.py	2026-10-17 17:44:26.422338598 -0400
+++ fixed.py	2026-10-17 17:44:26.811335981 -0400
@@ -6,4 +6,4 @@
     def __len__(self):
         return 1 if self.val else 0
 x = [CustomBool(1), CustomBool(0)]
-print(bool(x[(1, 0)]))
+print(bool(x[1, 0]))
r1-p008 · Walrus in Comprehension Late Binding
1funcs = []
2for i in range(2):
3 if (t := [(i, i+1)])[0]:
4 funcs.append(lambda: t)
5print([f() for f in funcs])
[[(1, 2)], [(1, 2)]]
r2-p001 · Keyword-only and positional-only argument forwarding
1def f(a, /, b, *, c=0): return (a, b, c)
2val = [1, 2]
3d = {(f(*val))[():]}
4print('before:', list(d))
5def g(a, /, b, *, c=0): return (a, b, c)
6val = [1, 2]
7d = {g(*val)[()]}
8print('after:', list(d))
r2-p002 · Walrus operator scope change
1d = {}
2if True:
3 d[(walrus := 1)] = 'inner'
4print('walrus in outer?', 'walrus' in locals())
5d = {}
6if True:
7 d[walrus := 1] = 'inner'
8print('walrus in outer?', 'walrus' in locals())
walrus in outer? True
walrus in outer? True
r2-p003 · Parenthesized expression vs tuple formation
1x = (42,)
2print('x is tuple:', isinstance(x, tuple), 'value:', x)
3x = 42,
4print('x is tuple:', isinstance(x, tuple), 'value:', x)
x is tuple: True value: (42,)
x is tuple: True value: (42,)
r2-p004 · Line continuation grouping hazard
1import sys
2idx = (
3 1,
4 2
5)
6d = {}
7d[idx] = 'value'
8print('dict value:', d[(1,
9 2)])
10idx = (
11 1,
12 2
13)
14d = {}
15d[idx] = 'value'
16print('dict value:', d[1,
17 2])
--- orig.py	2026-10-17 17:44:34.635283484 -0400
+++ fixed.py	2026-10-17 17:44:34.800282380 -0400
@@ -5,8 +5,8 @@
 )
 d = {}
 d[idx] = 'value'
-print('dict value:', d[(1,
-    2)])
+print('dict value:', d[1,
+    2])
 idx = (
     1,
     2
dict value: value
dict value: value
r2-p005 · Generator consumption difference
1def gen():
2 yield 1
3 yield 2
4g = gen()
5d = {}
6d[(next(g), next(g))] = 'got'
7print('first access:', d[(1, 2)])
8g = gen()
9try:
10 print('second access:', d[(next(g), next(g))])
11except StopIteration as e:
12 print('StopIteration:', e)
13g = gen()
14d = {}
15d[(next(g), next(g))] = 'got'
16print('first access:', d[(next(g), next(g))])
17g = gen()
18try:
19 print('second access:', d[(next(g), next(g))])
20except StopIteration as e:
21 print('StopIteration:', e)
--- orig.py	2026-10-17 17:44:34.907281664 -0400
+++ fixed.py	2026-10-17 17:44:35.285279135 -0400
@@ -3,19 +3,19 @@
     yield 2
 g = gen()
 d = {}
-d[(next(g), next(g))] = 'got'
-print('first access:', d[(1, 2)])
+d[next(g), next(g)] = 'got'
+print('first access:', d[1, 2])
 g = gen()
 try:
-    print('second access:', d[(next(g), next(g))])
+    print('second access:', d[next(g), next(g)])
 except StopIteration as e:
     print('StopIteration:', e)
 g = gen()
 d = {}
-d[(next(g), next(g))] = 'got'
-print('first access:', d[(next(g), next(g))])
+d[next(g), next(g)] = 'got'
+print('first access:', d[next(g), next(g)])
 g = gen()
 try:
-    print('second access:', d[(next(g), next(g))])
+    print('second access:', d[next(g), next(g)])
 except StopIteration as e:
     print('StopIteration:', e)
first access: got
second access: got
r2-p006 · Slice object interpretation in __getitem__
1class C:
2 def __getitem__(self, key):
3 if isinstance(key, tuple) and len(key) == 2:
4 return f'tuple-slice: {key}'
5 return f'other: {key}'
6c = C()
7print(c[(1, 2)])
8c = C()
9print(c[1, 2])
--- orig.py	2026-10-17 17:44:35.522277550 -0400
+++ fixed.py	2026-10-17 17:44:35.684276467 -0400
@@ -4,6 +4,6 @@
             return f'tuple-slice: {key}'
         return f'other: {key}'
 c = C()
-print(c[(1, 2)])
+print(c[1, 2])
 c = C()
 print(c[1, 2])
tuple-slice: (1, 2)
tuple-slice: (1, 2)
r2-p007 · Context manager without close()
1class Writer:
2 def __enter__(self):
3 self.data = []
4 return self
5 def __exit__(self, *exc):
6 pass
7 def write(self, s):
8 self.data.append(s)
9with Writer() as w:
10 w.write('hello')
11 idx = (0,)
12 lst = ['world']
13 lst[idx[0]] = w.data[0]
14print('lst:', lst)
15with Writer() as w:
16 w.write('hello')
17 idx = 0,
18 lst = ['world']
19 lst[idx[0]] = w.data[0]
20print('lst:', lst)
lst: ['hello']
lst: ['hello']
r2-p008 · Comment preservation hazard
1# comment before
2x = [10, 20]
3# important index
4i = [(0, 1)] # inline comment
5print(x[i[0][0]], x[i[0][1]])
6# comment before
7x = [10, 20]
8# important index
9i = [(0, 1)] # inline comment
10print(x[i[0][0]], x[i[0][1]])
10 20
10 20