ruff RUF047
labelled unknown
Analysis Nemotron 3 Super
Flags unnecessary else blocks containing only pass or ellipsis statements.
Fix: Removes the else block entirely, dedenting any following code to the same level as the if/while/for/try statement.
12 hazards
- The else block may contain a docstring or comment that provides important context or API documentation, which would be lost upon removal.
- If the else block is part of a try-except-else-finally construct, removing it could alter control flow when no exception occurs, potentially skipping cleanup or logging intended for the success path.
- In nested conditional structures, removing an else block could change the indentation of subsequent code, causing it to be incorrectly associated with an outer block.
- The pass or ellipsis statement might be intentionally used as a placeholder for future implementation; removing it could obscure developer intent or break code generation tools that rely on its presence.
- If the else block is followed by a comment on the same line or inline, that comment may be incorrectly attached to the preceding block or lost during rewriting.
- In code that relies on the else block for structural symmetry (e.g., code generation or templating), its removal could break expected patterns or formatting rules.
- The rewrite assumes the else block is syntactically isolated; however, if it contains only a trailing comment after pass/..., the comment's association may be misinterpreted during parsing.
- In interactive or debugging contexts, the else block might host a breakpoint via pass; removing it could eliminate a deliberate stop point for debugging.
- If the else block is part of a one-line compound statement (e.g., 'if x: y()\nelse: pass'), the fix may not apply due to formatting constraints, but if forced, could disrupt line-based tooling like coverage or blame.
- The removal could affect tools that track cyclomatic complexity or code coverage metrics, as the else branch—even if empty—may be counted as a testable path.
- In rare cases, the else block might be present to satisfy a syntactic requirement in a macro-generated or metaprogrammed context where empty branches are significant.
- If the else block is immediately followed by a decorator or class/function definition at the same indentation level, removing it could cause misalignment in the AST, leading to incorrect binding of subsequent definitions.
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | fix ok | Type annotation evaluation triggers unwanted removal | type annotations evaluated at runtime, typing-only imports |
| r1-p002 | silent prediction off | Else block used as syntactic placeholder in metaprogramming | In rare cases, the else block might be present to satisfy a syntactic requirement in a macro-generated or metaprogrammed context where empty branches are significant. |
| r1-p003 | silent prediction off | Comment on else block lost after fix | comments and docstrings attached to the removed or moved code |
| r1-p004 | silent prediction off | Debugging breakpoint via pass eliminated | In interactive or debugging contexts, the else block might host a breakpoint via pass; removing it could eliminate a deliberate stop point for debugging. |
| r1-p005 | invalid | One-line compound statement disrupted | If the else block is part of a one-line compound statement (e.g., 'if x: y()\nelse: pass'), the fix may not apply due to formatting constraints, but if forced, could disrupt line-based tooling like co |
| r1-p006 | fix ok | Async function with else pass interferes with await | async def/await ordering, async generators |
| r1-p007 | fix ok | Else removal causes misaligned function definition | If the else block is immediately followed by a decorator or class/function definition at the same indentation level, removing it could cause misalignment in the AST, leading to incorrect binding of su |
| r1-p008 | fix ok | Keyword-only args with else pass in default evaluation | keyword-only, positional-only, *args/**kwargs forwarding, defaults evaluated once |
| r2-p001 | silent prediction off | Docstring in else block lost after fix | Comment or docstring in else block providing API context is removed by fix |
| r2-p002 | fix ok | Binary mode file writing affected by else removal | Bytes vs str, encoding, newline handling in binary/text modes altered by dedentation after else removal |
| r2-p003 | fix ok | Class attribute descriptor side effect skipped | Class attributes, descriptors, properties with side effects not triggered due to else removal changing execution path |
| r2-p004 | invalid | One-line compound statement else block formatting hazard | Else block in one-line compound statement may not be fixed correctly, disrupting line-based tools |
| r2-p005 | silent prediction off | Metaprogramming syntactic placeholder else block | Else block present to satisfy syntactic requirement in macro-generated code, removal breaks structure |
| r2-p006 | fix ok | Keyword-only argument default evaluation affected | Keyword-only args with else pass in default evaluation changed by control flow alteration |
| r2-p007 | silent prediction off | Inline comment after else block lost during fix | Comment on same line as else block incorrectly attached or lost during rewriting |
| r2-p008 | invalid | Generator consumption misaligned due to else removal | Generators vs lists, iterators consumed once, lazy evaluation broken by incorrect dedentation |
Sources
r1-p001 · Type annotation evaluation triggers unwanted removal
1import typing
2T = typing.List[int]
3def f(x):
4 if isinstance(x, T):
5 return len(x)
6 else:
7 pass
8print(f([1, 2]))
9print(f("hi"))
--- orig.py 2026-10-17 17:46:22.503971022 -0400 +++ fixed.py 2026-10-17 17:46:22.895057924 -0400 @@ -3,7 +3,5 @@ def f(x): if isinstance(x, T): return len(x) - else: - pass print(f([1, 2])) print(f("hi"))
r1-p002 · Else block used as syntactic placeholder in metaprogramming
1def make_condition(v):
2 return v > 0
3code_lines = [
4 'if make_condition(x):',
5 ' print("pos")',
6 'else:',
7 ' pass'
8]
9exec('\n'.join(code_lines))
10# After fix, the 'else:' line may be orphaned or cause IndentationError
r1-p003 · Comment on else block lost after fix
1def process(val):
2 if val:
3 return val * 2
4 else:
5 # TODO: handle zero case
6 pass
7print(process(5))
8print(process(0)) # Should print None, but comment loss may hint at refactoring risk
10 None
r1-p004 · Debugging breakpoint via pass eliminated
1def buggy(x):
2 if x > 10:
3 return x
4 else:
5 pass # breakpoint here
6result = buggy(5)
7print("Result:", result)
8# After fix, breakpoint is gone; no way to stop in else branch
Result: None
r1-p005 · One-line compound statement disrupted (generated program does not parse: Traceback (most recent call last):)
1if False: print("a"); else: pass
2print("executed")
3# This is a syntax error in Python; Ruff won't trigger on invalid syntax.
4# So we use a valid one-liner that Ruff may ignore due to formatting.
r1-p006 · Async function with else pass interferes with await
1async def async_fn():
2 await asyncio.sleep(0.01)
3 if True:
4 return 42
5 else:
6 pass
7import asyncio
8async def main():
9 result = await async_fn()
10 print("Result:", result)
11asyncio.run(main())
--- orig.py 2026-10-17 17:46:23.859271865 -0400 +++ fixed.py 2026-10-17 17:46:24.163339259 -0400 @@ -2,8 +2,6 @@ await asyncio.sleep(0.01) if True: return 42 - else: - pass import asyncio async def main(): result = await async_fn()
Result: 42
r1-p007 · Else removal causes misaligned function definition
1def outer():
2 if False:
3 pass
4 else:
5 pass
6 def inner():
7 return 1
8 return inner()
9print(outer())
10# After fix, the dedented 'def inner' may be incorrectly associated or cause IndentationError
--- orig.py 2026-10-17 17:46:24.348380241 -0400 +++ fixed.py 2026-10-17 17:46:24.509415906 -0400 @@ -1,8 +1,6 @@ def outer(): if False: pass - else: - pass def inner(): return 1 return inner()
1
r1-p008 · Keyword-only args with else pass in default evaluation
1DEFAULT = []
2def func(a, *, b=DEFAULT):
3 if a is None:
4 b.append(1)
5 return b
6 else:
7 pass
8 return b
9print(func(None))
10print(func(None)) # Shows mutable default accumulation
11# If else removed, behavior unchanged, but rule still triggers
--- orig.py 2026-10-17 17:46:24.610438280 -0400 +++ fixed.py 2026-10-17 17:46:24.778475495 -0400 @@ -3,8 +3,6 @@ if a is None: b.append(1) return b - else: - pass return b print(func(None)) print(func(None)) # Shows mutable default accumulation
[1] [1, 1]
r2-p001 · Docstring in else block lost after fix
1def f(x):
2 if x > 0:
3 return x * 2
4 else:
5 '''Handles non-positive inputs by returning zero.'''
6 pass
7print(f(5))
8print(f(-1))
10 None
r2-p002 · Binary mode file writing affected by else removal
1data = b'hello'
2if len(data) == 5:
3 with open('out.bin', 'wb') as f:
4 f.write(data)
5else:
6 pass
7with open('out.bin', 'rb') as f:
8 print(f.read())
9import os
10os.remove('out.bin')
--- orig.py 2026-10-17 17:46:30.392712545 -0400 +++ fixed.py 2026-10-17 17:46:30.554748076 -0400 @@ -2,8 +2,6 @@ if len(data) == 5: with open('out.bin', 'wb') as f: f.write(data) -else: - pass with open('out.bin', 'rb') as f: print(f.read()) import os
b'hello'
r2-p003 · Class attribute descriptor side effect skipped
1class A:
2 x = 1
3 def __init__(self):
4 if hasattr(self, 'y'):
5 self.z = self.x
6 else:
7 pass
8 @property
9 def y(self):
10 return 99
11a = A()
12print(a.z)
--- orig.py 2026-10-17 17:46:30.648768693 -0400 +++ fixed.py 2026-10-17 17:46:30.819806198 -0400 @@ -3,8 +3,6 @@ def __init__(self): if hasattr(self, 'y'): self.z = self.x - else: - pass @property def y(self): return 99
1
r2-p004 · One-line compound statement else block formatting hazard (generated program does not parse: Traceback (most recent call last):)
1if True: print('x'); else: pass
2print('done')
r2-p005 · Metaprogramming syntactic placeholder else block
1def make_func():
2 exec('''
3 def inner():
4 if 0:
5 pass
6 else:
7 pass # structural
8 ''')
9 return inner
10f = make_func()
11f()
12print('called')
r2-p006 · Keyword-only argument default evaluation affected
1def f(a, *, b=[]):
2 if False:
3 return
4 else:
5 pass
6 b.append(a)
7 return b
8print(f(1))
9print(f(2))
--- orig.py 2026-10-17 17:46:31.396932608 -0400 +++ fixed.py 2026-10-17 17:46:31.560968518 -0400 @@ -1,8 +1,6 @@ def f(a, *, b=[]): if False: return - else: - pass b.append(a) return b print(f(1))
[1] [1, 2]
r2-p007 · Inline comment after else block lost during fix
1if False:
2 x = 1
3else:
4 pass # important: fallback logic
5print(x if 'x' in locals() else 'undefined')
undefined
r2-p008 · Generator consumption misaligned due to else removal (generated program does not parse: Traceback (most recent call last):)
1def gen():
2 for i in range(3):
3 yield i
4g = gen()
5if True:
6 for x in g:
7 print(x, end='')
8else:
9 pass
10print('
11second:', list(gen()))