ruff UP018
labelled unknown
Analysis Nemotron 3 Super
Flags redundant constructor calls like str(x), bytes(b), int(n), float(f), bool(v), complex(c) where x is already of the target type.
Fix: Replace the constructor call with its literal equivalent: e.g., str(s) → s when s is a string literal, bytes(b) → b when b is a bytes literal, etc.
12 hazards
- Rewriting str(expr) to expr changes behavior if expr has side effects (e.g., str(print("x")) vs print("x"))
- Rewriting bytes(expr) to expr alters evaluation if expr is a function call with side effects
- Rewriting int(expr) to expr fails if expr is a float (e.g., int(3.9) → 3.9 changes value and type)
- Rewriting float(expr) to expr breaks if expr is an integer string (e.g., float("4") → "4" raises TypeError in numeric contexts)
- Rewriting bool(expr) to expr changes truthiness semantics (e.g., bool([]) → [] is falsy but not equivalent in explicit bool checks)
- Rewriting complex(expr) to expr fails if expr is a real number (e.g., complex(5) → 5 loses imaginary part and changes type)
- The fix may drop inline comments attached to the constructor call (e.g., str("hi") # comment → "hi" # comment becomes detached or lost)
- If the constructor name is shadowed locally (e.g., str = lambda x: x; str("a")), the rewrite to "a" ignores the custom behavior
- In eval or exec contexts, replacing str(...) with its argument may alter namespace resolution if the argument is a variable
- The rewrite is invalid if the argument is a tuple needing parentheses for disambiguation (e.g., str((1,2)) → (1,2) is fine, but str(1,2) is a syntax error so not fired)
- If the constructor is used as a callable in higher-order code (e.g., map(str, [...]))
- Rewriting may interfere with debugging or profiling tools that rely on constructor call sites
Findings
| program | oracle | label | judge | status | summary |
|---|---|---|---|---|---|
| r1-p003 | fix-changes-behavior | labelled safe | real · medium | no match | The rule rewrites the string literal 'int(5)' inside a type annotation to '5', changing the annotation's stored value from 'int(5)' to '5'. Since annotations a… |
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | silent prediction off | complex_reduction_loses_imaginary_part | Rewriting complex(expr) to expr fails if expr is a real number because it discards the imaginary part and changes the type from complex to int/float. |
| r1-p002 | fix ok | bytes_str_mode_mismatch | Rewriting bytes(b'data') to b'data' interacts with I/O mode; writing bytes to a text-mode file raises TypeError while str would encode implicitly. |
| r1-p003 | fix-changes-behavior | type_annotation_runtime_eval | Rewriting int(5) to 5 removes a constructor call that might be used in a forward reference or string annotation evaluated at runtime via typing.get_type_hints(). |
| r1-p004 | silent | star_import_side_effects_all | Rewriting bool(True) to True affects module-level execution under star imports if the constructor call had side effects (though bool doesn't, we simulate via a wrapper that logs). |
| r1-p005 | fix ok | dict_ordering_duplicate_keys | Rewriting float(3.14) to 3.14 changes nothing for value, but if used in a dict key construction during comprehension, order and deduplication could be affected by evaluation timing. |
| r1-p006 | fix ok | comments_docstrings_attached | Removing str('hello') also removes any inline comment or docstring attached to that line, which may be relied upon by tools or documentation. |
| r1-p007 | fix ok | string_formatting_edge_cases | Rewriting repr vs str matters: str(42) vs repr(42) are same for int, but for str, str('"hi"') vs repr('"hi"') differ in quotes. |
| r1-p008 | silent prediction off | debugging_profiler_call_sites | Rewriting complex(1+2j) to (1+2j) removes a call site that profilers or debuggers might break on or trace; line numbers shift. |
| r2-p001 | fix ok | star_imports_sideeffects_all_hazard | star-imports, module-level side effects, __all__ |
| r2-p002 | silent | bool_truthiness_semantics_hazard | Rewriting bool(expr) to expr changes truthiness semantics (e.g., bool([]) → [] is falsy but not equivalent in explicit bool checks) |
| r2-p003 | silent prediction off | str_sideeffects_hazard | Rewriting str(expr) to expr changes behavior if expr has side effects (e.g., str(print("x")) vs print("x")) |
| r2-p004 | silent prediction off | eval_order_sideeffects_merge_hazard | evaluation order and side effects when expressions are merged, duplicated or deleted |
| r2-p005 | silent prediction off | eval_exec_namespace_resolution_hazard | In eval or exec contexts, replacing str(...) with its argument may alter namespace resolution if the argument is a variable |
| r2-p006 | silent prediction off | mutable_default_args_aliasing_hazard | mutable default arguments and aliasing after a rewrite |
| r2-p007 | silent prediction off | int_float_truncation_hazard | Rewriting int(expr) to expr fails if expr is a float (e.g., int(3.9) → 3.9 changes value and type) |
| r2-p008 | fix ok | comments_docstrings_attached_hazard | comments and docstrings attached to the removed or moved code |
Sources
r1-p001 · complex_reduction_loses_imaginary_part
1def f():
2 z = complex(5)
3 return z.real, z.imag
4print(f())
(5.0, 0.0)
r1-p002 · bytes_str_mode_mismatch
1with open('test.bin', 'wb') as f:
2 f.write(bytes(b'hello\n'))
3with open('test.bin', 'rb') as f:
4 print(f.read())
--- orig.py 2026-10-17 17:17:29.275647485 -0400 +++ fixed.py 2026-10-17 17:17:29.439637653 -0400 @@ -1,4 +1,4 @@ with open('test.bin', 'wb') as f: - f.write(bytes(b'hello\n')) + f.write(b'hello\n') with open('test.bin', 'rb') as f: print(f.read())
b'hello\n'
r1-p003 · type_annotation_runtime_eval
1from __future__ import annotations
2def f(x: 'int(5)'):
3 return x
4print(f.__annotations__['x'])
--- orig.py 2026-10-17 17:17:29.537631778 -0400 +++ fixed.py 2026-10-17 17:17:29.697622187 -0400 @@ -1,4 +1,4 @@ from __future__ import annotations -def f(x: 'int(5)'): +def f(x: '5'): return x print(f.__annotations__['x'])
'int(5)'
r1-p004 · star_import_side_effects_all
1LOG = []
2def bool(x):
3 LOG.append(('bool', x))
4 return __builtins__.bool(x)
5print(bool(True))
6print(LOG)
True
[('bool', True)]r1-p005 · dict_ordering_duplicate_keys
1keys = [float(3.14), float(3.14)]
2d = {k: None for k in keys}
3print(list(d.keys()))
--- orig.py 2026-10-17 17:17:29.929608279 -0400 +++ fixed.py 2026-10-17 17:17:30.107597620 -0400 @@ -1,3 +1,3 @@ -keys = [float(3.14), float(3.14)] +keys = [3.14, 3.14] d = {k: None for k in keys} print(list(d.keys()))
[3.14]
r1-p006 · comments_docstrings_attached
1msg = str('hello') # This is a greeting
2print(msg)
--- orig.py 2026-10-17 17:17:30.212591337 -0400 +++ fixed.py 2026-10-17 17:17:30.373581703 -0400 @@ -1,2 +1,2 @@ -msg = str('hello') # This is a greeting +msg = 'hello' # This is a greeting print(msg)
hello
r1-p007 · string_formatting_edge_cases
1s = str('"hi"')
2print(repr(s))
3print(s)
--- orig.py 2026-10-17 17:17:30.475575599 -0400 +++ fixed.py 2026-10-17 17:17:30.640565725 -0400 @@ -1,3 +1,3 @@ -s = str('"hi"') +s = '"hi"' print(repr(s)) print(s)
'"hi"' "hi"
r1-p008 · debugging_profiler_call_sites
1import traceback
2def g():
3 return complex(1+2j)
4def f():
5 return g()
6try:
7 raise ValueError
8except:
9 tb = traceback.format_exc()
10 print('complex' in tb)
False
r2-p001 · star_imports_sideeffects_all_hazard
1__all__ = ['value']
2value = str('hello') # This is the exported value
3def get_value():
4 return value
5print(get_value())
--- orig.py 2026-10-17 17:18:04.515599907 -0400 +++ fixed.py 2026-10-17 17:18:04.680590622 -0400 @@ -1,5 +1,5 @@ __all__ = ['value'] -value = str('hello') # This is the exported value +value = 'hello' # This is the exported value def get_value(): return value print(get_value())
hello
r2-p002 · bool_truthiness_semantics_hazard
1lst = []
2if bool(lst):
3 print('truthy')
4else:
5 print('falsy')
6if lst: # same as bool(lst) but different identity
7 print('list truthy')
8else:
9 print('list falsy')
falsy list falsy
r2-p003 · str_sideeffects_hazard
1def f():
2 print('side effect')
3 return 'ok'
4result = str(f())
5print('result:', result)
side effect result: ok
r2-p004 · eval_order_sideeffects_merge_hazard
1i = 0
2def inc():
3 global i
4 i += 1
5 return i
6vals = [str(inc()), str(inc())]
7print('vals:', vals, 'i:', i)
vals: ['1', '2'] i: 2
r2-p005 · eval_exec_namespace_resolution_hazard
1x = 'hidden'
2def test():
3 x = 'local'
4 return str(x)
5print(test())
6exec('print(str(x))') # uses global x
local hidden
r2-p006 · mutable_default_args_aliasing_hazard
1def append_to(val, lst=str([])): # rule triggers here
2 lst.append(val)
3 return lst
4print(append_to(1))
5print(append_to(2))
r2-p007 · int_float_truncation_hazard
1f = 3.9
2n = int(f)
3print(f'int({f}) = {n}, type: {type(n)}')
4if n == f:
5 print('equal')
6else:
7 print('not equal')
int(3.9) = 3, type: <class 'int'> not equal
r2-p008 · comments_docstrings_attached_hazard
1def process_data():
2 """Process input data.
3 This function uses str('ready') to signal readiness.
4 """
5 status = str('ready') # ready signal
6 return status
--- orig.py 2026-10-17 17:18:05.790528239 -0400 +++ fixed.py 2026-10-17 17:18:05.950519252 -0400 @@ -2,5 +2,5 @@ """Process input data. This function uses str('ready') to signal readiness. """ - status = str('ready') # ready signal + status = 'ready' # ready signal return status