ruff UP048
labelled unknown
Analysis Nemotron 3 Super
Flags `while 1:` loops and suggests replacing them with `while True:` for clarity.
Fix: Replace the literal integer 1 in the while condition with the boolean literal True, preserving all whitespace and formatting otherwise.
11 hazards
- The rewrite changes the constant from int to bool, which could affect code that relies on the condition's type via type() or isinstance() checks.
- If the loop condition is used in an expression elsewhere (e.g., assigned to a variable), the type change may break downstream logic expecting an integer.
- In rare metaprogramming contexts where the AST node's constant value is inspected, the rewrite alters the observed value from 1 to True.
- If the code is processed by tools that distinguish between 1 and True for optimization or serialization, the transformation may alter output.
- Comments attached to the condition token (e.g., trailing comments on the same line) may be misplaced or lost during reformatting depending on the linter's formatting logic.
- If the while statement is part of a larger compound statement parsed ambiguously, the rewrite could interfere with error recovery or parsing in malformed code snippets.
- In code that deliberately uses 1 as a truthy integer for bitwise operations in the condition (though syntactically invalid as a standalone condition), the rewrite would not apply since such usage isn't a valid while condition.
- The fix assumes the condition is a simple literal; if the condition were a more complex expression mistakenly parsed as '1' due to broken syntax, the rewrite could be incorrectly applied.
- Changing 1 to True may affect debugging or introspection tools that display constant values in stack traces or frame locals.
- If the code is run under a Python interpreter that treats 1 and True differently in edge cases (e.g., certain PyPy optimizations or sandboxed environments), behavioral differences could emerge.
- In code that overrides the built-in True name in an outer scope (though irrelevant for the condition's evaluation), the rewrite might be misinterpreted as referencing the outer scope, though this does not change runtime behavior since True is resolved at compile time.
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | fix ok | Context manager interaction | context managers that are not files, objects with write() but no close() |
| r1-p002 | fix ok | Coercion and Decimal arithmetic | int/float/bool coercion, Decimal, division and rounding |
| r1-p003 | fix ok | Async generator interaction | async def/await ordering, async generators |
| r1-p004 | invalid | Dict ordering and hashing | dict ordering, duplicate keys, __hash__/__eq__ overrides, sets |
| r1-p005 | fix ok prediction off | Serialization distinction | If the code is processed by tools that distinguish between 1 and True for optimization or serialization, the transformation may alter output. |
| r1-p006 | fix ok | Generator consumption | generators vs lists, iterators consumed once, lazy vs eager evaluation |
| r1-p007 | silent prediction off | AST constant inspection | In rare metaprogramming contexts where the AST node's constant value is inspected, the rewrite alters the observed value from 1 to True. |
| r1-p008 | fix ok | Keyword-only argument forwarding | keyword-only, positional-only, *args/**kwargs forwarded, defaults evaluated once |
| r2-p001 | fix ok | Dict ordering with duplicate keys and custom hash/eq | dict ordering, duplicate keys, __hash__/__eq__ overrides, sets |
| r2-p002 | fix ok | Debugging/introspection visibility of constants in frame | Changing 1 to True may affect debugging or introspection tools that display constant values in stack traces or frame locals. |
| r2-p003 | fix ok | Evaluation order and side effects in merged expressions | evaluation order and side effects when expressions are merged, duplicated or deleted |
| r2-p004 | fix ok | File modes, truncation, partial writes, non-str data | file modes and truncation, partial writes, non-str data passed to write |
| r2-p005 | invalid | Shadowed builtins and names redefined later | shadowed builtins and names redefined later in the module |
| r2-p006 | silent | Bitwise truthy integer in condition (near-miss: invalid syntax, so expect no trigger) | In code that deliberately uses 1 as a truthy integer for bitwise operations in the condition (though syntactically invalid as a standalone condition), the rewrite would not apply since such usage isn' |
| r2-p007 | fix ok | Type annotations evaluated at runtime, typing-only imports | type annotations evaluated at runtime, typing-only imports |
| r2-p008 | fix ok | Star-imports, module-level side effects, __all__ | star-imports, module-level side effects, __all__ |
Sources
r1-p001 · Context manager interaction
1class Dummy:
2 def __enter__(self):
3 return self
4 def __exit__(self, *exc):
5 pass
6 def write(self, s):
7 self.data += s
8 return len(s)
9
10out = []
11with Dummy() as d:
12 d.data = ''
13 i = 0
14 while 1:
15 if i >= 2:
16 break
17 d.write(str(i))
18 i += 1
19 out.append(d.data)
20print(''.join(out))
--- orig.py 2026-10-17 17:27:33.121300495 -0400 +++ fixed.py 2026-10-17 17:27:33.306296530 -0400 @@ -11,7 +11,7 @@ with Dummy() as d: d.data = '' i = 0 - while 1: + while True: if i >= 2: break d.write(str(i))
01
r1-p002 · Coercion and Decimal arithmetic
1from decimal import Decimal, getcontext
2getcontext().prec = 6
3vals = []
4i = 0
5while 1:
6 if i == 3:
7 break
8 f = float(i) / 2
9 d = Decimal(str(f))
10 vals.append((f, d))
11 i += 1
12print(vals)
--- orig.py 2026-10-17 17:27:33.405294407 -0400 +++ fixed.py 2026-10-17 17:27:33.586290527 -0400 @@ -2,7 +2,7 @@ getcontext().prec = 6 vals = [] i = 0 -while 1: +while True: if i == 3: break f = float(i) / 2
[(0.0, Decimal('0.0')), (0.5, Decimal('0.5')), (1.0, Decimal('1.0'))]r1-p003 · Async generator interaction
1async def gen():
2 i = 0
3 while 1:
4 if i >= 2:
5 break
6 yield i
7 i += 1
8
9async def main():
10 res = []
11 async for x in gen():
12 res.append(x)
13 print(res)
14
15import asyncio
16asyncio.run(main())
--- orig.py 2026-10-17 17:27:33.693288234 -0400 +++ fixed.py 2026-10-17 17:27:34.019281246 -0400 @@ -1,6 +1,6 @@ async def gen(): i = 0 - while 1: + while True: if i >= 2: break yield i
[0, 1]
r1-p004 · Dict ordering and hashing (generated program does not terminate within the time limit)
1class BadKey:
2 def __init__(self, v):
3 self.v = v
4 def __hash__(self):
5 return hash(int(self.v))
6 def __eq__(self, other):
7 return isinstance(other, BadKey) and self.v == other.v
8
9m = {}
10k = BadKey(1)
11while 1:
12 if k in m:
13 break
14 m[k] = 'found'
15 k.v += 1
16print(list(m.keys()))
r1-p005 · Serialization distinction
1# This program checks if any tool distinguishes 1 vs True.
2# Since no such tool is used in stdlib execution,
3# we expect no behavioral change.
4# We still include a while 1: to satisfy the rule trigger.
5print('start')
6i = 0
7while 1:
8 if i:
9 break
10 i += 1
11print('end')
--- orig.py 2026-10-17 17:27:39.279169043 -0400 +++ fixed.py 2026-10-17 17:27:39.438165666 -0400 @@ -4,7 +4,7 @@ # We still include a while 1: to satisfy the rule trigger. print('start') i = 0 -while 1: +while True: if i: break i += 1
start end
r1-p006 · Generator consumption
1def make_gen():
2 i = 0
3 while 1:
4 if i >= 3:
5 break
6 yield i
7 i += 1
8
9g = make_gen()
10first = list(g)
11second = list(g) # exhausted
12print(len(first), len(second))
--- orig.py 2026-10-17 17:27:39.539163521 -0400 +++ fixed.py 2026-10-17 17:27:39.699160123 -0400 @@ -1,6 +1,6 @@ def make_gen(): i = 0 - while 1: + while True: if i >= 3: break yield i
3 0
r1-p007 · AST constant inspection
1import ast
2code = 'while 1:\n break'
3tree = ast.parse(code, mode='exec')
4wh_node = tree.body[0]
5const = wh_node.test # the condition
6if isinstance(const, ast.Constant):
7 print(const.value)
8else:
9 print(type(const))
1
r1-p008 · Keyword-only argument forwarding
1def outer(**kwargs):
2 def inner(*, limit=1):
3 i = 0
4 total = 0
5 while 1:
6 if i >= limit:
7 break
8 total += i
9 i += 1
10 return total
11 return inner(**kwargs)
12
13print(outer(limit=3))
--- orig.py 2026-10-17 17:27:39.932155175 -0400 +++ fixed.py 2026-10-17 17:27:40.107151462 -0400 @@ -2,7 +2,7 @@ def inner(*, limit=1): i = 0 total = 0 - while 1: + while True: if i >= limit: break total += i
3
r2-p001 · Dict ordering with duplicate keys and custom hash/eq
1class K:
2 def __init__(self, v):
3 self.v = v
4 def __hash__(self):
5 return hash(self.v)
6 def __eq__(self, other):
7 return isinstance(other, K) and self.v == other.v
8
9m = {}
10while 1:
11 m[K(1)] = 'a'
12 m[K(1)] = 'b' # duplicate key
13 break
14
15# Print to show dict size and values (depends on loop having run)
16print(len(m))
17for k, v in m.items():
18 print(f'{k.v}:{v}')
--- orig.py 2026-10-17 17:27:45.503037451 -0400 +++ fixed.py 2026-10-17 17:27:45.666034021 -0400 @@ -7,7 +7,7 @@ return isinstance(other, K) and self.v == other.v m = {} -while 1: +while True: m[K(1)] = 'a' m[K(1)] = 'b' # duplicate key break
1 1:b
r2-p002 · Debugging/introspection visibility of constants in frame
1def f():
2 while 1:
3 x = 1
4 y = True
5 # Frame inspection: show locals
6 frame = __import__('sys')._getframe(0)
7 print('x:', frame.f_locals['x'], type(frame.f_locals['x']))
8 print('y:', frame.f_locals['y'], type(frame.f_locals['y']))
9 break
10f()
--- orig.py 2026-10-17 17:27:45.769031854 -0400 +++ fixed.py 2026-10-17 17:27:45.932028425 -0400 @@ -1,5 +1,5 @@ def f(): - while 1: + while True: x = 1 y = True # Frame inspection: show locals
x: 1 <class 'int'> y: True <class 'bool'>
r2-p003 · Evaluation order and side effects in merged expressions
1i = 0
2while 1:
3 if i >= 2:
4 break
5 print(i)
6 i += 1
7# After loop, i should be 2
8print('final i:', i)
--- orig.py 2026-10-17 17:27:46.030026364 -0400 +++ fixed.py 2026-10-17 17:27:46.190023002 -0400 @@ -1,5 +1,5 @@ i = 0 -while 1: +while True: if i >= 2: break print(i)
0 1 final i: 2
r2-p004 · File modes, truncation, partial writes, non-str data
1with open('test.txt', 'w') as f:
2 while 1:
3 f.write(b'hello') # bytes, not str
4 break
5with open('test.txt', 'rb') as f:
6 data = f.read()
7 print(data)
8import os
9os.remove('test.txt')
--- orig.py 2026-10-17 17:27:46.295020796 -0400 +++ fixed.py 2026-10-17 17:27:46.679012729 -0400 @@ -1,5 +1,5 @@ with open('test.txt', 'w') as f: - while 1: + while True: f.write(b'hello') # bytes, not str break with open('test.txt', 'rb') as f:
r2-p005 · Shadowed builtins and names redefined later (generated program does not parse: Traceback (most recent call last):)
1True = 1 # shadow built-in True
2while 1:
3 print(True, type(True)) # Should be 1, int
4 break
5# Restore? Not needed; show effect
6print('After loop, True =', True, type(True))
7del True # restore built-in if possible
8try:
9 print(True)
10except Exception as e:
11 print(type(e).__name__, e)
r2-p006 · Bitwise truthy integer in condition (near-miss: invalid syntax, so expect no trigger)
1# This is invalid syntax; cannot be compiled.
2# while 1 & 1:
3# pass
4# Instead, show a valid loop that does not trigger because condition is not literal 1
5x = 1
6while x & 1: # x is variable, not literal
7 print(x)
8 x = 0
9print('done')
1 done
r2-p007 · Type annotations evaluated at runtime, typing-only imports
1from typing import List
2# Use annotation at runtime via __annotations__
3def f() -> List[int]:
4 while 1:
5 return [1]
6
7# Trigger annotation evaluation
8print(f.__annotations__['return'])
9# Call f to ensure loop ran
10print(f())
--- orig.py 2026-10-17 17:27:47.155002734 -0400 +++ fixed.py 2026-10-17 17:27:47.354998539 -0400 @@ -1,7 +1,7 @@ from typing import List # Use annotation at runtime via __annotations__ def f() -> List[int]: - while 1: + while True: return [1] # Trigger annotation evaluation
typing.List[int] [1]
r2-p008 · Star-imports, module-level side effects, __all__
1__all__ = ['mod_val']
2mod_val = 1
3
4# Simulate star-import by exec
5ns = {}
6exec("from test_mod import *", ns, ns)
7# But we can't create file; instead, define inline and import
8# Use a trick: define a module-like dict and exec
9code = '''
10__all__ = ['mod_val']
11mod_val = 1
12'''
13local_ns = {}
14exec(code, local_ns, local_ns)
15# Now simulate while loop using imported-like name
16while 1:
17 print(local_ns['mod_val'])
18 break
--- orig.py 2026-10-17 17:27:47.471996085 -0400 +++ fixed.py 2026-10-17 17:27:47.865987820 -0400 @@ -13,6 +13,6 @@ local_ns = {} exec(code, local_ns, local_ns) # Now simulate while loop using imported-like name -while 1: +while True: print(local_ns['mod_val']) break