ruff UP034
labelled unknown
Analysis Nemotron 3 Super
Flags unnecessary parentheses around expressions where they do not affect precedence or grouping.
Fix: Removes the outer pair of parentheses when they enclose a single expression and are not required for operator precedence, tuple creation, or semantic clarity.
12 hazards
- Rewriting `return (yield x)` to `return yield x` changes it from yielding a value and returning None to a syntax error due to invalid yield placement.
- Removing parentheses in `(lambda: x)()` alters grouping, causing the lambda to be applied to `x` instead of being called first.
- Stripping parentheses from `((x))` may break code relying on the inner parentheses for visual grouping or tooling expectations, though semantically identical.
- In `(x,)`, removing outer parentheses yields `x,`, which is still a tuple, but if mistakenly applied to `(x)` it becomes `x`, changing a tuple to a scalar.
- For `f((x, y))`, removing outer parentheses gives `f(x, y)`, which unpacks the tuple and passes two arguments instead of one tuple argument.
- In `assert (condition), message`, removing parentheses around `condition` results in `assert condition, message`, which is valid, but if applied to `(assert condition), message` it would break — however, the rule does not target this shape.
- Comments immediately after the opening parenthesis like `(# comment x)` would be lost if the autofix removes the parentheses without preserving internal formatting.
- In a tuple assignment like `((a, b)) = ((c, d))`, removing outer parentheses gives `(a, b) = (c, d)`, which is equivalent, but if nested incorrectly could be misapplied.
- In `raise (Exception("err"))`, removing parentheses yields `raise Exception("err")`, which is equivalent, but if the expression were more complex, precedence might matter — though the rule avoids such cases.
- In `[(i) for i in range(10)]`, removing parentheses yields `[i for i in range(10)]`, which is equivalent, but if the parentheses were part of a larger expression like `[(i) + 1]`, removal would change meaning — however, the rule does not fire there due to presence of `+`.
- In f-strings like `f"{(x)}"`, the rule does not apply as it targets expressions outside string contexts; applying it incorrectly would break the f-string syntax.
- In `isinstance((x), int)`, removing outer parentheses gives `isinstance(x, int)`, which is equivalent, but if written as `isinstance((x,), int)`, removing outer parentheses yields `isinstance(x,, int)` which is invalid — however, the rule does not fire on `(x,)` as it's a tuple.
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | silent prediction off | Lambda call grouping hazard | Removing parentheses in `(lambda: x)()` changes grouping from calling the lambda then applying result to x, to defining a lambda that takes x as argument. |
| r1-p002 | silent | F-string brace hazard | Incorrectly removing parentheses in f"{(x)}" would break f-string syntax, but rule correctly does not target expressions inside string literals. |
| r1-p003 | silent prediction off | List comprehension parentheses hazard | Rule removes parens in [(i) for i in range(10)] safely; hazard shown by contrast with [(i) + 1] where rule does not fire due to + operator. |
| r1-p004 | silent prediction off | Exception handling with finally/else | Rewriting raise (ValueError('')) inside try block; finally/else clauses execute deterministically to show rewriting did not alter control flow. |
| r1-p005 | silent prediction off | Singleton tuple vs scalar hazard | Removing parentheses from (x,) yields x, (still tuple), but from (x) yields x (scalar); rule avoids (x,) due to comma. |
| r1-p006 | silent prediction off | Tuple assignment nesting hazard | Rule removes outer parens in ((a, b)) = ((c, d)) safely; incorrect nesting could misapply but rule does not target inner structures. |
| r1-p007 | silent prediction off | Assert message form hazard | Rule removes parens around condition in assert (cond), msg safely; does not fire on (assert cond), msg which would be invalid. |
| r1-p008 | silent prediction off | Raise expression parentheses hazard | Rule removes parens in raise (Exception('err')) safely; complex expressions avoided by rule due to precedence concerns. |
| r2-p001 | silent prediction off | Raise exception parentheses - safe removal | Precedence in complex raise expressions |
| r2-p002 | fix ok | Singleton tuple vs scalar confusion | (x,) remains tuple after fix, (x) becomes scalar |
| r2-p003 | silent | Context manager close behavior | Non-file context manager with write but no close |
| r2-p004 | silent prediction off | Comment inside parentheses lost on rewrite | Comments after ( are stripped when parens removed |
| r2-p005 | fix ok | Function call with tuple argument unpacking hazard | f((x,y)) -> f(x,y) changes arg count |
| r2-p006 | silent | Binary vs text file mode encoding | Bytes vs str in file I/O with encoding/newline |
| r2-p007 | silent | isinstance with tuple vs scalar hazard (near-miss) | isinstance((x),int) safe; isinstance((x,),int) not triggered by rule |
| r2-p008 | silent | Custom __bool__ and truthiness | Truth value testing with custom __bool__ |
Sources
r1-p001 · Lambda call grouping hazard
1x = 2
2result = (lambda: x)()
3print('Result:', result)
Result: 2
r1-p002 · F-string brace hazard
1x = 42
2s = f"{(x)}"
3print('F-string:', s)
F-string: 42
r1-p003 · List comprehension parentheses hazard
1vals = [(i) for i in range(3)]
2print('List comp:', vals)
3# Near-miss: parentheses here are not removed due to +
4vals2 = [(i) + 1 for i in range(3)]
5print('With plus:', vals2)
List comp: [0, 1, 2] With plus: [1, 2, 3]
r1-p004 · Exception handling with finally/else
1try:
2 raise (ValueError('error'))
3except ValueError as e:
4 print('Caught:', str(e))
5else:
6 print('No exception')
7finally:
8 print('Finally block')
Caught: error Finally block
r1-p005 · Singleton tuple vs scalar hazard
1t = (5,)
2print('Tuple:', t, type(t))
3s = (5)
4print('Scalar:', s, type(s))
Tuple: (5,) <class 'tuple'> Scalar: 5 <class 'int'>
r1-p006 · Tuple assignment nesting hazard
1(a, b) = (1, 2)
2((c, d)) = ((3, 4))
3print('Assigned:', a, b, c, d)
Assigned: 1 2 3 4
r1-p007 · Assert message form hazard
1x = 5
2assert (x > 0), 'x positive'
3print('Assert passed')
Assert passed
r1-p008 · Raise expression parentheses hazard
1try:
2 raise (Exception('test'))
3except Exception as e:
4 print('Raised caught:', type(e).__name__, str(e))
Raised caught: Exception test
r2-p001 · Raise exception parentheses - safe removal
1import sys
2try:
3 raise (ValueError('err'))
4except ValueError as e:
5 print('Caught:', e)
Caught: err
r2-p002 · Singleton tuple vs scalar confusion
1def show(val):
2 print(type(val).__name__, val)
3x = 5
4show((x))
5show((x,))
--- orig.py 2026-10-17 17:20:29.470414771 -0400 +++ fixed.py 2026-10-17 17:20:29.643407252 -0400 @@ -1,5 +1,5 @@ def show(val): print(type(val).__name__, val) x = 5 -show((x)) +show(x) show((x,))
int 5 tuple (5,)
r2-p003 · Context manager close behavior
1class Writer:
2 def __enter__(self): return self
3 def __exit__(self, *exc): pass
4 def write(self, s): self.data = s
5with (Writer()) as w:
6 w.write('test')
7print(getattr(w, 'data', 'none'))
test
r2-p004 · Comment inside parentheses lost on rewrite
1x = (# note
242)
3print('x =', x)
x = 42
r2-p005 · Function call with tuple argument unpacking hazard
1def f(*args):
2 print('len', len(args), 'args', args)
3t = (1, 2)
4f((t))
--- orig.py 2026-10-17 17:20:30.012391216 -0400 +++ fixed.py 2026-10-17 17:20:30.174384187 -0400 @@ -1,4 +1,4 @@ def f(*args): print('len', len(args), 'args', args) t = (1, 2) -f((t)) +f(t)
len 1 args ((1, 2),)
r2-p006 · Binary vs text file mode encoding
1with open('test.bin', 'wb') as f:
2 f.write(b'hello\n')
3with open('test.bin', 'rb') as f:
4 data = f.read()
5print('bytes:', repr(data))
6with open('test.txt', 'w', encoding='utf-8') as f:
7 f.write('hello\n')
8with open('test.txt', 'r', encoding='utf-8') as f:
9 data = f.read()
10print('text:', repr(data))
11import os
12os.remove('test.bin')
13os.remove('test.txt')
bytes: b'hello\n' text: 'hello\n'
r2-p007 · isinstance with tuple vs scalar hazard (near-miss)
1x = 5
2print(isinstance((x), int))
3print(isinstance((x,), int))
True False
r2-p008 · Custom __bool__ and truthiness
1class Num:
2 def __init__(self, n): self.n = n
3 def __bool__(self): return self.n != 0
4x = Num(0)
5if (x):
6 print('true')
7else:
8 print('false')
false