fixhunt

ruff B014

labelled unknown
Runs / 2026-10-17T20-13-47-843Z-iyev-ruff-B014ruff 0.17.12026-10-17 20:13 UTC8 programs × 2 round(s)16 programs, 0 fired, 0 fixed, 0 findings, 0 rejectedmodel cost $0.0034

Analysis Nemotron 3 Super

Flags except clauses containing duplicate or redundant exception types where one type subsumes another.

Fix: Removes redundant exception types from the except tuple, keeping only the most general (superclass) exception when a subtype is present, or deduplicates identical types, preserving the original order of non-redundant types.

12 hazards
  • Rewriting `except (Exception, ValueError):` to `except Exception:` changes behavior if the handler relies on `ValueError` being matched first for conditional logic inside the handler, though such logic is unreachable anyway.
  • If the except clause contains a comment after a redundant type like `except (Exception, # keep ValueError):`, the autofix may incorrectly remove or misplace the comment during tuple restructuring.
  • When the except clause is part of a larger compound statement with line continuations, the rewrite may alter formatting in a way that breaks parsing if the tool does not preserve exact whitespace or parentheses structure.
  • In code that uses stringized exceptions via `from __future__ import annotations`, the autofix might not correctly resolve forward references, leading to incorrect removal or retention of types.
  • If the except tuple contains a variable name that shadows an exception class (e.g., `ValueError = 5; except (Exception, ValueError):`), the rewrite incorrectly treats it as a type and may produce invalid syntax or change meaning.
  • The autofix may fail to recognize that a user-defined exception inherits from a built-in, leading to incomplete redundancy removal and leaving the code still flagged.
  • In nested try statements, rewriting an outer except clause may affect the control flow of inner handlers if exceptions are re-raised, though this is unlikely due to redundancy.
  • If the except clause is followed by a `finally` block, the rewrite does not affect finally execution, but removing redundant types could be misconstrued as altering exception propagation timing—though it does not.
  • When the except clause uses a bare `except:` (no arguments), the rule does not fire, but if mistakenly applied, the fix would break syntax by introducing an empty tuple.
  • If the code depends on the exact tuple object for introspection (e.g., storing the except clause via `inspect`), the rewritten tuple may differ in identity or content, affecting metaprogramming.
  • Autofix may leave a trailing comma in a singleton tuple (e.g., `except (Exception,):`) which is valid but may trigger style warnings in strict codebases.
  • In code processed by tools that rely on the AST node's exact source representation (e.g., certain refactoring tools), the rewritten source may break source-to-AST roundtripping.

Programs

idresulttitlehazard
r1-p001silent prediction offString Formatting Edge Cases - % Operatorstring formatting edge cases: %, format, f-strings, repr vs str, nested quotes
r1-p002silent prediction offGenerators vs Lists - Iterator Consumptiongenerators vs lists, iterators consumed once, lazy vs eager evaluation
r1-p003silent prediction offTrailing Comma in Singleton TupleAutofix may leave a trailing comma in a singleton tuple (e.g., `except (Exception,):`) which is valid but may trigger style warnings in strict codebases.
r1-p004silent prediction offFinally Block InteractionIf the except clause is followed by a `finally` block, the rewrite does not affect finally execution, but removing redundant types could be misconstrued as altering exception propagation timing—though
r1-p005silent prediction offHandler Conditional Logic DependencyRewriting `except (Exception, ValueError):` to `except Exception:` changes behavior if the handler relies on `ValueError` being matched first for conditional logic inside the handler, though such logi
r1-p006silent prediction offComments Attached to Removed Codecomments and docstrings attached to the removed or moved code
r1-p007silentRuntime Type Annotations Evaluationtype annotations evaluated at runtime, typing-only imports
r1-p008silent prediction offTruthiness and Identity Checkstruthiness of custom __bool__/__len__, None vs falsy, 'is' vs '=='
r2-p001silent prediction offComment Preservation During Redundant Except RewriteComments attached to redundant exception types may be lost or misplaced during autofix.
r2-p002silent prediction offAST Roundtrip Integrity After Except RewriteRewritten except tuple may break source-to-AST roundtripping in tools relying on exact source form.
r2-p003silent prediction offVariable Shadowing Exception Class in Except TupleWhen a variable shadows an exception class (e.g., ValueError=5), the linter may mistakenly treat it as a type and rewrite incorrectly.
r2-p004silent prediction offExcept Rewrite Followed by Finally BlockAutofix of except clause does not alter finally execution, but may be misconstrued as changing propagation timing.
r2-p005silentContext Manager Without Close() MethodUsing non-file context managers that implement write() but not close() — unrelated to except rewrite but exercises resource handling patterns.
r2-p006silent prediction offExcept Tuple Used for Introspection via inspectStoring the except clause tuple for introspection (e.g., via inspect) may break if autofix changes tuple identity or content.
r2-p007silentBytes vs Str Encoding in Except-Related I/OMixing bytes and str in I/O operations within except handlers — encoding/newline hazards unrelated to rewrite but sensitive to type changes.
r2-p008silent prediction offAsync Generator and Await Ordering in Except HandlerInteraction between async def/await ordering and except clause rewrite — ensuring await happens correctly after potential fix.

Sources

r1-p001 · String Formatting Edge Cases - % Operator
1try:
2 x = '%s' % [1, 2]
3except (TypeError, ValueError):
4 print('caught:', type(e).__name__)
r1-p002 · Generators vs Lists - Iterator Consumption
1def gen():
2 yield 1
3 yield 2
4g = gen()
5try:
6 next(g)
7 next(g)
8 next(g)
9except (StopIteration, Exception):
10 print('caught:', type(e).__name__)
r1-p003 · Trailing Comma in Singleton Tuple
1try:
2 int('a')
3except (ValueError,):
4 print('value error caught')
value error caught
r1-p004 · Finally Block Interaction
1try:
2 1/0
3except (ZeroDivisionError, ArithmeticError):
4 print('except')
5finally:
6 print('finally')
except
finally
r1-p005 · Handler Conditional Logic Dependency
1try:
2 int('x')
3except (Exception, ValueError) as e:
4 if isinstance(e, ValueError):
5 print('value error path')
6 else:
7 print('other error:', type(e).__name__)
value error path
r1-p006 · Comments Attached to Removed Code
1try:
2 [] + {}
3except (TypeError, Exception): # TypeError is more specific
4 print('type error')
type error
r1-p007 · Runtime Type Annotations Evaluation
1from typing import List
2try:
3 [1, 2] + 'a'
4except (TypeError,):
5 print('type error')
type error
r1-p008 · Truthiness and Identity Checks
1class Fake:
2 def __bool__(self): return False
3try:
4 bool(Fake())
5except (Exception, ValueError):
6 print('no exception raised')
7except:
8 print('unexpected')
r2-p001 · Comment Preservation During Redundant Except Rewrite
1# Test comment preservation
2try:
3 raise ValueError
4except (Exception, # keep this comment
5 ValueError): # this should stay
6 print('Caught:', type(__import__('sys').exc_info()[1]).__name__)
7else:
8 print('No exception')
9finally:
10 print('Finally ran')
Caught: ValueError
Finally ran
r2-p002 · AST Roundtrip Integrity After Except Rewrite
1import ast
2src = '''\
3try:
4 1/0
5except (ZeroDivisionError, Exception):\
6 pass'''
7tree = ast.parse(src)
8fixed = ast.unparse(tree) # May not preserve original tuple form
9print('Original:', repr(src))
10print('Unparsed:', repr(fixed))
11try:
12 exec(fixed)
13except Exception as e:
14 print('Error in fixed code:', type(e).__name__)
Original: 'try:\n    1/0\nexcept (ZeroDivisionError, Exception):    pass'
Unparsed: 'try:\n    1 / 0\nexcept (ZeroDivisionError, Exception):\n    pass'
r2-p003 · Variable Shadowing Exception Class in Except Tuple
1ValueError = 42 # shadows built-in
2try:
3 raise ValueError # raises the variable (int), not exception
4except (Exception, ValueError): # linter sees two 'types', may dedupe
5 print('Caught:', type(__import__('sys').exc_info()[1]))
6 print('Value is:', ValueError)
7except TypeError:
8 print('Got TypeError as expected')
r2-p004 · Except Rewrite Followed by Finally Block
1def test():
2 try:
3 raise OSError('disk error')
4 except (OSError, IOError): # IOError is subclass of OSError in Python 3
5 print('Handler: OSError caught')
6 return 'from_except'
7 finally:
8 print('Finally: always runs')
9 return 'from_finally'
10result = test()
11print('Result:', result)
Handler: OSError caught
Finally: always runs
Result: from_finally
r2-p005 · Context Manager Without Close() Method
1class WriteOnly:
2 def __enter__(self):
3 self.data = []
4 return self
5 def write(self, x):
6 self.data.append(x)
7 def __exit__(self, *args):
8 pass
9
10with WriteOnly() as w:
11 w.write('hello')
12 w.write('world')
13print('Written:', ''.join(w.data))
Written: helloworld
r2-p006 · Except Tuple Used for Introspection via inspect
1import inspect
2
3def func():
4 try:
5 raise ValueError
6 except (ValueError, TypeError): # not redundant, so rule should not fire
7 pass
8
9handler_tuple = None
10for name, cell in inspect.getclosurevars(func).nonlocals.items():
11 if isinstance(cell, tuple) and all(isinstance(t, type) for t in cell):
12 handler_tuple = cell
13 break
14
15print('Handler tuple:', handler_tuple)
16print('Length:', len(handler_tuple) if handler_tuple else 0)
17print('Types:', [t.__name__ for t in handler_tuple] if handler_tuple else [])
Handler tuple: None
Length: 0
Types: []
r2-p007 · Bytes vs Str Encoding in Except-Related I/O
1try:
2 with open('test.bin', 'wb') as f:
3 f.write(b'hello\n')
4 with open('test.bin', 'rb') as f:
5 data = f.read()
6 print('Raw bytes:', repr(data))
7 try:
8 text = data.decode('utf-8')
9 print('Decoded:', repr(text))
10 except UnicodeDecodeError as ude:
11 print('Decode failed:', ude)
12except (OSError, IOError): # redundant: IOError is alias for OSError
13 print('File error caught')
14finally:
15 import os
16 try: os.remove('test.bin')
17 except: pass
Raw bytes: b'hello\n'
Decoded: 'hello\n'
r2-p008 · Async Generator and Await Ordering in Except Handler
1async def maybe_fail():
2 await asyncio.sleep(0) # yield control
3 raise ValueError('async error')
4
5async def main():
6 try:
7 await maybe_fail()
8 except (ValueError, Exception): # ValueError subsumed by Exception
9 print('Caught ValueError')
10 return 42
11 finally:
12 print('Finally in async')
13
14import asyncio
15result = asyncio.run(main())
16print('Result:', result)
Caught ValueError
Finally in async
Result: 42