fixhunt

ruff PLR1711

labelled unknown
Runs / 2026-10-17T21-00-59-090Z-4m0i-ruff-PLR1711ruff 0.17.12026-10-17 21:00 UTC8 programs × 2 round(s)16 programs, 8 fired, 8 fixed, 0 findings, 1 rejectedmodel cost $0.0043

Analysis Nemotron 3 Super

Flags functions ending with an explicit 'return' or 'return None' when they contain no other return statements.

Fix: Removes the final 'return' or 'return None' statement from the function body, preserving any trailing comment on the same line if present.

10 hazards
  • If the function contains a nested function that uses 'return' to escape to the outer function, removing the outer return may alter control flow.
  • If the 'return' statement is inside a try block and the finally block raises an exception, removing the return may change which exception propagates.
  • If the function is overridden in a subclass and the super() call relies on the implicit None return, changing the return may affect cooperative multiple inheritance behavior.
  • If the return statement is followed by a type ignore comment on the same line, removing the line may drop the ignore and cause type-checking errors.
  • If the function is part of a protocol or interface that expects an explicit return None for documentation or tooling purposes, removing it may break tooling assumptions.
  • If the return statement is the only statement in a function body and the function is used in a context where its __code__.co_flags is inspected, removing the return may change the flag set (e.g., CO_NOFREE).
  • If the function contains a late-bound closure that captures a variable defined after the return (unreachable), removing the return does not affect behavior but may mislead readers about reachability.
  • If the return statement is written as 'return (expr)' where expr is a parenthesized expression with side effects, removing it may suppress those side effects (though the rule does not fire if there are other returns, this case is prevented by the 'no other returns' condition).
  • If the function is decorated with a decorator that inspects the bytecode for the presence of a RETURN_VALUE instruction, removing the return may change the decorator's behavior.
  • If the function is invoked via a frame hack (e.g., sys._getframe) that checks f_lasti for the offset of a RETURN_VALUE, removing the return changes the last instruction offset.

Programs

idresulttitlehazard
r1-p001fix okWalrus operator affecting comprehension scopingwalrus, comprehensions scoping, late binding in closures and lambdas
r1-p002fix okString formatting with % and .format interacting via returned valuestring formatting edge cases: %, format, f-strings, repr vs str, nested quotes
r1-p003fix okBinary mode file write using returned buffer lengthbytes vs str, encoding and newline handling, text vs binary modes
r1-p004fix okProperty with side effect accessed after implicit None returnclass attributes vs instance attributes, descriptors, properties with side effects
r1-p005fix okNested function escaping via return alters outer flowIf the function contains a nested function that uses 'return' to escape to the outer function, removing the outer return may alter control flow.
r1-p006silentTry-finally where finally raises overriding return pathIf the 'return' statement is inside a try block and the finally block raises an exception, removing the return may change which exception propagates.
r1-p007fix okMutable default argument list alias across callsmutable default arguments and aliasing after a rewrite
r1-p008silent prediction offCustom bool and len return None used in truth testtruthiness of custom __bool__/__len__, None vs falsy, 'is' vs '=='
r2-p001invaliddict_ordering_duplicate_keys_hash_eq_setdict ordering, duplicate keys, __hash__/__eq__ overrides, sets
r2-p002fix okframe_hack_f_lasti_return_value_offsetIf the function is invoked via a frame hack (e.g., sys._getframe) that checks f_lasti for the offset of a RETURN_VALUE, removing the return changes the last instruction offset.
r2-p003silent prediction offtype_ignore_comment_on_same_line_droppedIf the return statement is followed by a type ignore comment on the same line, removing the line may drop the ignore and cause type-checking errors.
r2-p004silent prediction offevaluation_order_side_effects_expressions_merged_deletedevaluation order and side effects when expressions are merged, duplicated or deleted
r2-p005silent prediction offclass_attributes_vs_instance_attributes_descriptors_properties_side_effectsclass attributes vs instance attributes, descriptors, properties with side effects
r2-p006fix oktruthiness_custom_bool_len_none_falsy_is_eqtruthiness of custom __bool__/__len__, None vs falsy, 'is' vs '=='
r2-p007silent prediction offfunction_used_in_context_where___code___co_flags_inspectedIf the return statement is the only statement in a function body and the function is used in a context where its __code__.co_flags is inspected, removing the return may change the flag set (e.g., CO_N
r2-p008silent prediction offcomments_and_docstrings_attached_to_removed_or_moved_codecomments and docstrings attached to the removed or moved code

Sources

r1-p001 · Walrus operator affecting comprehension scoping
1def f():
2 lst = [x := i*2 for i in range(2)]
3 return None
4print(f())
--- orig.py	2026-10-17 17:01:15.905400004 -0400
+++ fixed.py	2026-10-17 17:01:16.080402139 -0400
@@ -1,4 +1,3 @@
 def f():
     lst = [x := i*2 for i in range(2)]
-    return None
 print(f())
None
r1-p002 · String formatting with % and .format interacting via returned value
1def fmt(val):
2 s = '%s' % val
3 t = '{}{}'.format(s, '!')
4 return None
5r = fmt('A')
6print(r)
7s = fmt('B')
8if s is None:
9 print('got none')
--- orig.py	2026-10-17 17:01:16.182403384 -0400
+++ fixed.py	2026-10-17 17:01:16.352405458 -0400
@@ -1,7 +1,6 @@
 def fmt(val):
     s = '%s' % val
     t = '{}{}'.format(s, '!')
-    return None
 r = fmt('A')
 print(r)
 s = fmt('B')
None
got none
r1-p003 · Binary mode file write using returned buffer length
1def w():
2 data = b'hi'
3 with open('tmp.bin', 'wb') as fp:
4 n = fp.write(data)
5 return None
6n = w()
7with open('tmp.bin', 'rb') as fp:
8 print(fp.read())
9import os; os.remove('tmp.bin')
--- orig.py	2026-10-17 17:01:16.454406702 -0400
+++ fixed.py	2026-10-17 17:01:16.616408679 -0400
@@ -2,7 +2,6 @@
     data = b'hi'
     with open('tmp.bin', 'wb') as fp:
         n = fp.write(data)
-    return None
 n = w()
 with open('tmp.bin', 'rb') as fp:
     print(fp.read())
b'hi'
r1-p004 · Property with side effect accessed after implicit None return
1class C:
2 @property
3 def val(self):
4 self._seen = True
5 return 42
6def f():
7 c = C()
8 _ = c.val
9 return None
10f()
11c = C()
12print(hasattr(c, '_seen'))
--- orig.py	2026-10-17 17:01:16.720409948 -0400
+++ fixed.py	2026-10-17 17:01:16.889412010 -0400
@@ -6,7 +6,6 @@
 def f():
     c = C()
     _ = c.val
-    return None
 f()
 c = C()
 print(hasattr(c, '_seen'))
False
r1-p005 · Nested function escaping via return alters outer flow
1def f():
2 def g():
3 return 'escaped'
4 x = g()
5 y = x + ' more'
6 return None
7res = f()
8print(res)
--- orig.py	2026-10-17 17:01:17.002413388 -0400
+++ fixed.py	2026-10-17 17:01:17.173415474 -0400
@@ -3,6 +3,5 @@
         return 'escaped'
     x = g()
     y = x + ' more'
-    return None
 res = f()
 print(res)
None
r1-p006 · Try-finally where finally raises overriding return path
1def f():
2 try:
3 return 42
4 finally:
5 raise RuntimeError('finally wins')
6try:
7 f()
8except Exception as e:
9 print(type(e).__name__, str(e))
RuntimeError finally wins
r1-p007 · Mutable default argument list alias across calls
1def appender(item, lst=[]):
2 lst.append(item)
3 return None
4appender(1)
5appender(2)
6f = appender
7f.__defaults__[0].append(3)
8print(appender(0)[2])
--- orig.py	2026-10-17 17:01:17.417418449 -0400
+++ fixed.py	2026-10-17 17:01:17.812423267 -0400
@@ -1,6 +1,5 @@
 def appender(item, lst=[]):
     lst.append(item)
-    return None
 appender(1)
 appender(2)
 f = appender
r1-p008 · Custom bool and len return None used in truth test
1class T:
2 def __bool__(self):
3 return True
4 def __len__(self):
5 return 0
6def maker():
7 return T()
8x = maker()
9if x:
10 print('true')
11else:
12 print('false')
true
r2-p001 · dict_ordering_duplicate_keys_hash_eq_set (generated program is not deterministic)
1def f():
2 d = {}
3 class K:
4 def __init__(self, v): self.v = v
5 def __hash__(self): return hash(self.v)
6 def __eq__(self, other): return isinstance(other, K) and self.v == other.v
7 d[K(1)] = 'a'
8 d[K(1)] = 'b'
9 return d
10print(sorted(f().items()))
r2-p002 · frame_hack_f_lasti_return_value_offset
1import sys
2
3def f():
4 x = 1
5 y = 2
6 z = x + y
7 return
8
9frame = sys._getframe()
10f()
11offset = frame.f_lasti
12print('offset:', offset)
13if offset < 0:
14 print('negative')
15else:
16 print('non-negative')
--- orig.py	2026-10-17 17:01:24.499504684 -0400
+++ fixed.py	2026-10-17 17:01:24.665506702 -0400
@@ -4,7 +4,6 @@
     x = 1
     y = 2
     z = x + y
-    return
 
 frame = sys._getframe()
 f()
offset: 66
non-negative
r2-p003 · type_ignore_comment_on_same_line_dropped
1from typing import List
2
3def f() -> List[int]:
4 x = 1
5 return [x] # type: ignore[list-item]
6
7result = f()
8print(len(result))
9for item in result:
10 print(item)
1
1
r2-p004 · evaluation_order_side_effects_expressions_merged_deleted
1counter = 0
2
3def inc():
4 global counter
5 counter += 1
6 return counter
7
8def f():
9 a = inc()
10 b = inc()
11 return a + b
12
13print(f())
3
r2-p005 · class_attributes_vs_instance_attributes_descriptors_properties_side_effects
1class A:
2 x = 1
3 @property
4 def prop(self):
5 return self.x + 1
6
7def f():
8 a = A()
9 a.x = 2
10 return a.prop
11
12print(f())
3
r2-p006 · truthiness_custom_bool_len_none_falsy_is_eq
1class C:
2 def __bool__(self): return False
3 def __len__(self): return 1
4
5def f():
6 c = C()
7 return
8
9obj = f()
10if obj is None:
11 print('is None')
12else:
13 print('not None')
14if obj == None:
15 print('== None')
16else:
17 print('!= None')
18if obj:
19 print('truthy')
20else:
21 print('falsy')
--- orig.py	2026-10-17 17:01:25.186513036 -0400
+++ fixed.py	2026-10-17 17:01:25.359515138 -0400
@@ -4,7 +4,6 @@
 
 def f():
     c = C()
-    return
 
 obj = f()
 if obj is None:
is None
== None
falsy
r2-p007 · function_used_in_context_where___code___co_flags_inspected
1def f():
2 return
3
4code = f.__code__
5flags = code.co_flags
6print('CO_NOFREE set:', bool(flags & 0x20))
7print('CO_NEWLOCALS set:', bool(flags & 0x02))
CO_NOFREE set: False
CO_NEWLOCALS set: True
r2-p008 · comments_and_docstrings_attached_to_removed_or_moved_code
1def f():
2 """This is a docstring."""
3 x = 1 # inline comment
4 return x # trailing comment
5
6print(f.__doc__)
7print(f())
This is a docstring.
1