fixhunt

ruff RUF046

labelled unknown
Runs / 2026-10-17T21-45-18-816Z-cile-ruff-RUF046ruff 0.17.12026-10-17 21:45 UTC8 programs × 2 round(s)16 programs, 11 fired, 9 fixed, 1 findings, 0 rejectedmodel cost $0.02

Analysis Nemotron 3 Super

Flags redundant int() casts around expressions that are already guaranteed to be integers.

Fix: Removes the outer int() call, leaving only the inner expression unchanged.

10 hazards
  • Rewriting int(len(x)) to len(x) changes behavior if len(x) returns a non-integer type like a custom class with __len__ returning float, breaking type expectations.
  • Rewriting int(abs(y)) to abs(y) is unsafe if abs(y) returns a non-integer (e.g., Decimal or Fraction), altering numeric type and downstream operations.
  • Rewriting int(True) to True changes the type from int to bool, which may break isinstance(x, int) checks or arithmetic relying on int subclass behavior.
  • Rewriting int(False) to False similarly changes type from int to bool, potentially breaking logic that distinguishes 0 from False via type.
  • Rewriting int(__import__('sys').maxsize) to __import__('sys').maxsize is unsafe if the import has side effects or if the attribute lookup is expected to occur in a different context due to refactoring.
  • Rewriting int(5 + 3) to 5 + 3 is generally safe but may affect code relying on the explicit int conversion for documentation or type assertion purposes, though no semantic change occurs in standard integers.
  • Rewriting int(round(z)) to round(z) is unsafe if z defines __round__ returning a non-integer (e.g., float), as the int() cast would have truncated it to int, but removing it leaves a float, changing value and type.
  • Rewriting int(math.floor(w)) to math.floor(w) is unsafe if w defines __floor__ returning a non-integer (e.g., np.float64), as math.floor(w) would return that type, but the original int() cast forced it to int, altering subsequent integer-dependent operations.
  • The fix may disrupt formatting-dependent tools or linters that expect the int() call to be present for style consistency, even if semantically equivalent in simple cases.
  • If the int() call appears in a larger expression like int(f()) + 1, removing it could alter evaluation order if f() has side effects and the surrounding code relies on left-to-right execution, though pure expression replacement preserves order — hazard arises only if the fix is incorrectly applied to non-isolated calls.

Findings

programoraclelabeljudgestatussummary
r1-p005fix-changes-behaviorlabelled safeintrospection-only · lowrelatedThe fix removes the redundant `int()` call from the lambda's source code, which changes the text returned by `inspect.getsource`. This is purely a source-code …

Programs

idresulttitlehazard
r1-p001fix okGenerators vs ListsRewriting int(len(x)) when x is a generator consumes it, breaking subsequent use; list preserves it.
r1-p002silent prediction offBool Subtype HazardRewriting int(True) to True changes type from int to bool, breaking isinstance checks expecting int.
r1-p003silent prediction offImport Side EffectRewriting int(__import__('sys').maxsize) assumes import is pure; but module init may have side effects expected to occur once.
r1-p004fired, no fixRound Returns FloatRewriting int(round(z)) to round(z) is unsafe if __round__ returns float; int() truncates, removing it leaves float.
r1-p005fix-changes-behaviorFormatting Tool DependencyRewriting int(5+3) may break formatters that rely on the int() call for alignment or style metrics, even if value unchanged.
r1-p006fix ok prediction offDescriptor Side EffectsRewriting int(getattr(obj, 'x', 0)) is silent, but if getattr triggers a descriptor with side effects, removing int() doesn't remove those — yet the rule doesn't fire here. Instead, we show a case whe
r1-p007fix okContext Manager Write OnlyRewriting int(len(context_manager)) is nonsensical, but we show a case where int() fires on len() of a list that was meant to be managed, and removing int() doesn't affect cm — but we use a context ma
r1-p008fix ok prediction offPathlib vs os.pathRewriting int(len(path)) where path is a pathlib.Path or os.path string; but len() behaves same. Instead, we show int() on a path operation that returns int-like but is not, e.g., Path.stat().st_size
r2-p001fix okDocumentation intent via int() on literal sumRewriting int(5 + 3) to 5 + 3 is generally safe but may affect code relying on the explicit int conversion for documentation or type assertion purposes.
r2-p002fix okString formatting with % operator and int()string formatting edge cases: %, format, f-strings, repr vs str, nested quotes
r2-p003fix okDict ordering with duplicate keys and hashdict ordering, duplicate keys, __hash__/__eq__ overrides, sets
r2-p004silent prediction offEvaluation order with side effects in argumentevaluation order and side effects when expressions are merged, duplicated or deleted
r2-p005fix okGenerator consumed by len() in int()generators vs lists, iterators consumed once, lazy vs eager evaluation
r2-p006silentMutable default argument and aliasingmutable default arguments and aliasing after a rewrite
r2-p007fired, no fixUnsafe removal of int() around round() with float returnRewriting int(round(z)) to round(z) is unsafe if z defines __round__ returning a non-integer (e.g., float), as the int() cast would have truncated it to int, but removing it leaves a float, changing v
r2-p008silent prediction offint() in larger expression with side effectIf the int() call appears in a larger expression like int(f()) + 1, removing it could alter evaluation order if f() has side effects and the surrounding code relies on left-to-right execution, though

Sources

r1-p001 · Generators vs Lists
1def f():
2 yield 1
3 yield 2
4
5g = f()
6lst = list(f())
7a = int(len(g))
8b = len(g)
9c = int(len(lst))
10d = len(lst)
11print('gen len after int:', a, 'remaining:', b)
12print('list len after int:', c, 'remaining:', d)
--- orig.py	2026-10-17 17:45:33.447897457 -0400
+++ fixed.py	2026-10-17 17:45:33.836894952 -0400
@@ -4,9 +4,9 @@
 
 g = f()
 lst = list(f())
-a = int(len(g))
+a = len(g)
 b = len(g)
-c = int(len(lst))
+c = len(lst)
 d = len(lst)
 print('gen len after int:', a, 'remaining:', b)
 print('list len after int:', c, 'remaining:', d)
r1-p002 · Bool Subtype Hazard
1def check_int(x):
2 return isinstance(x, int) and not isinstance(x, bool)
3
4v = int(True)
5print('int(True) is int?', isinstance(v, int))
6print('int(True) passes check_int?', check_int(v))
7print('type(int(True)):', type(v))
int(True) is int? True
int(True) passes check_int? True
type(int(True)): <class 'int'>
r1-p003 · Import Side Effect
1import sys
2counter = [0]
3orig_import = __import__
4def side_effect_import(name, *args, **kwargs):
5 if name == 'sys':
6 counter[0] += 1
7 return orig_import(name, *args, **kwargs)
8
9# Temporarily replace __import__ to observe side effects
10builtins = __import__('builtins')
11builtins.__import__ = side_effect_import
12try:
13 v = int(__import__('sys').maxsize)
14 print('sys imported', counter[0], 'times')
15 print('value:', v)
16except Exception as e:
17 print('error:', type(e).__name__, str(e))
18finally:
19 builtins.__import__ = orig_import
sys imported 1 times
value: 9223372036854775807
r1-p004 · Round Returns Float
1class FloatRound:
2 def __round__(self, ndigits=0):
3 return 3.14
4
5z = FloatRound()
6v = int(round(z))
7print('int(round(z)):', v, type(v))
8# After fix: round(z) -> 3.14 (float)
9# So we simulate by showing what round(z) gives
10print('round(z):', round(z), type(round(z)))
int(round(z)): 3 <class 'int'>
round(z): 3.14 <class 'float'>
r1-p005 · Formatting Tool Dependency
1# This line's length affects flake8 or black line length scoring
2val = int(5 + 3) # kept for formatting
3print('Value:', val)
4# If removed: 'val = 5 + 3' is shorter; tools may reformat differently
5# We show the line length as proxy
6import inspect
7import textwrap
8src = inspect.getsource(lambda: int(5 + 3))
9print('Source length of int(5+3):', len(src.strip()))
--- orig.py	2026-10-17 17:45:34.478890819 -0400
+++ fixed.py	2026-10-17 17:45:34.693889435 -0400
@@ -1,9 +1,9 @@
 # This line's length affects flake8 or black line length scoring
-val = int(5 + 3)  # kept for formatting
+val = 5 + 3  # kept for formatting
 print('Value:', val)
 # If removed: 'val = 5 + 3' is shorter; tools may reformat differently
 # We show the line length as proxy
 import inspect
 import textwrap
-src = inspect.getsource(lambda: int(5 + 3))
+src = inspect.getsource(lambda: (5 + 3))
 print('Source length of int(5+3):', len(src.strip()))
Value: 8
Source length of int(5+3): 43
r1-p006 · Descriptor Side Effects
1class Descriptor:
2 def __get__(self, obj, objtype):
3 print('Descriptor accessed')
4 return 42
5
6class Obj:
7 x = Descriptor()
8
9o = Obj()
10# Rule does NOT fire on getattr because argument not plain int-compatible
11# But we show a firing case with side effects in argument: len([descr access])
12def get_list():
13 print('get_list called')
14 return [o.x] # accessing descriptor
15
16try:
17 v = int(len(get_list()))
18 print('Result:', v)
19except Exception as e:
20 print('Error:', type(e).__name__, str(e))
--- orig.py	2026-10-17 17:45:34.814888657 -0400
+++ fixed.py	2026-10-17 17:45:34.984887563 -0400
@@ -14,7 +14,7 @@
     return [o.x]  # accessing descriptor
 
 try:
-    v = int(len(get_list()))
+    v = len(get_list())
     print('Result:', v)
 except Exception as e:
     print('Error:', type(e).__name__, str(e))
get_list called
Descriptor accessed
Result: 1
r1-p007 · Context Manager Write Only
1class ListManager:
2 def __enter__(self):
3 self.data = [1, 2, 3]
4 return self.data
5 def __exit__(self, *exc):
6 pass
7
8with ListManager() as lm:
9 a = int(len(lm))
10 b = len(lm)
11 print('int(len(lm)):', a, 'type:', type(a))
12 print('len(lm):', b, 'type:', type(b))
13# After fix: a = len(lm) -> same value, but type int either way
14# So we show that without int(), if someone expects bool from non-zero? No.
15# Instead: show that the value is used in a context where type matters
16print('a is int:', isinstance(a, int))
17print('b is int:', isinstance(b, int))
--- orig.py	2026-10-17 17:45:35.078886958 -0400
+++ fixed.py	2026-10-17 17:45:35.247885871 -0400
@@ -6,7 +6,7 @@
         pass
 
 with ListManager() as lm:
-    a = int(len(lm))
+    a = len(lm)
     b = len(lm)
     print('int(len(lm)):', a, 'type:', type(a))
     print('len(lm):', b, 'type:', type(b))
int(len(lm)): 3 type: <class 'int'>
len(lm): 3 type: <class 'int'>
a is int: True
b is int: True
r1-p008 · Pathlib vs os.path
1import os
2import pathlib
3# Create a temporary file
4with open('test.txt', 'w') as f:
5 f.write('hello')
6
7# Rule fires on int(len(...)) if we use len on something that is not plain int-compatible? No.
8# Instead, we show int() on a path-derived int that is safe, but we use it in a loop
9for i in range(2):
10 if i == 0:
11 l = int(len(os.path.abspath('test.txt')))
12 else:
13 l = int(len(str(pathlib.Path('test.txt').resolve())))
14 print(f'Iter {i}: length = {l}')
15
16# Cleanup
17os.remove('test.txt')
--- orig.py	2026-10-17 17:45:35.345885241 -0400
+++ fixed.py	2026-10-17 17:45:35.544883961 -0400
@@ -8,9 +8,9 @@
 # Instead, we show int() on a path-derived int that is safe, but we use it in a loop
 for i in range(2):
     if i == 0:
-        l = int(len(os.path.abspath('test.txt')))
+        l = len(os.path.abspath('test.txt'))
     else:
-        l = int(len(str(pathlib.Path('test.txt').resolve())))
+        l = len(str(pathlib.Path('test.txt').resolve()))
     print(f'Iter {i}: length = {l}')
 
 # Cleanup
Iter 0: length = 86
Iter 1: length = 86
r2-p001 · Documentation intent via int() on literal sum
1def get_value():
2 return int(5 + 3)
3
4print(get_value(), type(get_value()))
--- orig.py	2026-10-17 17:45:39.971855526 -0400
+++ fixed.py	2026-10-17 17:45:40.132854494 -0400
@@ -1,4 +1,4 @@
 def get_value():
-    return int(5 + 3)
+    return 5 + 3
 
 print(get_value(), type(get_value()))
8 <class 'int'>
r2-p002 · String formatting with % operator and int()
1x = 42
2result = '%d' % int(5 + 3)
3print(result)
--- orig.py	2026-10-17 17:45:40.239853808 -0400
+++ fixed.py	2026-10-17 17:45:40.395852807 -0400
@@ -1,3 +1,3 @@
 x = 42
-result = '%d' % int(5 + 3)
+result = '%d' % (5 + 3)
 print(result)
8
r2-p003 · Dict ordering with duplicate keys and hash
1class BadHash:
2 def __init__(self, v): self.v = v
3 def __hash__(self): return int(5 + 3)
4 def __eq__(self, other): return self.v == other.v
5
6d = {BadHash(1): 'a', BadHash(2): 'b'}
7print(len(d))
--- orig.py	2026-10-17 17:45:40.500852134 -0400
+++ fixed.py	2026-10-17 17:45:40.658851121 -0400
@@ -1,6 +1,6 @@
 class BadHash:
     def __init__(self, v): self.v = v
-    def __hash__(self): return int(5 + 3)
+    def __hash__(self): return 5 + 3
     def __eq__(self, other): return self.v == other.v
 
 d = {BadHash(1): 'a', BadHash(2): 'b'}
2
r2-p004 · Evaluation order with side effects in argument
1counter = 0
2
3def side_effect():
4 global counter
5 counter += 1
6 return 5
7
8print(int(side_effect() + 3), counter)
8 1
r2-p005 · Generator consumed by len() in int()
1def gen():
2 yield 1
3 yield 2
4 yield 3
5
6g = gen()
7print(int(len(list(g))))
8print(list(g))
--- orig.py	2026-10-17 17:45:40.888849646 -0400
+++ fixed.py	2026-10-17 17:45:41.050848608 -0400
@@ -4,5 +4,5 @@
     yield 3
 
 g = gen()
-print(int(len(list(g))))
+print(len(list(g)))
 print(list(g))
3
[]
r2-p006 · Mutable default argument and aliasing
1def f(x=[]):
2 x.append(1)
3 return len(x)
4
5print(f())
6print(f())
1
2
r2-p007 · Unsafe removal of int() around round() with float return
1class FloatRound:
2 def __round__(self, ndigits):
3 return 3.5
4
5z = FloatRound()
6print(int(round(z)), type(int(round(z))))
7print(round(z), type(round(z)))
r2-p008 · int() in larger expression with side effect
1counter = 0
2
3def f():
4 global counter
5 counter += 1
6 return 5
7
8print(int(f()) + 1, counter)
6 1