fixhunt

ruff FURB103

labelled unknown
Runs / 2026-10-23T03-46-37-103Z-x323-ruff-FURB103ruff 0.17.12026-10-23 03:46 UTC2 programs × 1 round(s)2 programs, 1 fired, 1 fixed, 0 findings, 0 rejectedmodel cost $0.0014

Analysis Nemotron 3 Super

Flags manual file writes using open() and .write() when they can be replaced with pathlib.Path.write_text() or write_bytes().

Fix: Replaces the with-open-write block with a direct call to pathlib.Path(file_path).write_text(content) or write_bytes(data), preserving the file path and written content while removing the variable assignment and block structure.

10 hazards
  • The rewrite removes the file handle variable (f), breaking any subsequent use of f after the write but before the block ends.
  • If the write call is not the last statement in the block, the fix incorrectly truncates the block and drops later statements.
  • The fix assumes the file is opened solely for writing; modes like 'r+' or 'a+' are not equivalent to write_text/write_bytes and may alter behavior.
  • Comments attached to the 'with' line, 'as f:', or indentation are discarded during the rewrite, violating comment preservation expectations.
  • The rewrite does not preserve custom openers, buffering, or errors parameters, which may affect I/O behavior in edge cases.
  • If the file path expression has side effects (e.g., function call), duplicating it in Path() changes evaluation timing and frequency.
  • When the written data is a complex expression, the fix may alter evaluation order relative to other expressions in the surrounding scope.
  • The generated code lacks the implicit file closing guaranteed by the context manager, though write_text/write_bytes handle closure internally—this is safe only if no exceptions occur mid-write.
  • If 'open' or 'Path' is shadowed by a local variable, the fix may bind to the wrong identifier, altering semantics.
  • The fix introduces a new import dependency on pathlib; if the module does not already import Path, the rewrite may cause a NameError unless the tool adds the import.

Programs

idresulttitlehazard
r1-p001fix okstar_import_side_effect_allFURB103 triggered inside a loop over __all__; after star import shadows Path causing mis-resolution
r1-p002silent prediction offshadowed_builtins_redeclaredShadowing open then restoring it lets second use show if first was rewritten incorrectly

Sources

r1-p001 · star_import_side_effect_all
1import os
2from pathlib import *
3def main():
4 __all__ = ['p']
5 p = lambda x: None
6 txt = b'data'
7 for name in __all__:
8 if name == 'p':
9 continue
10 try:
11 with open('tmp.bin', 'wb') as f:
12 f.write(txt)
13 break
14 except TypeError as e:
15 print(e)
16 try:
17 v = Path('tmp.bin').read_bytes()
18 print(v)
19 except Exception as e:
20 print(type(e).__name__, e)
21 finally:
22 if os.path.exists('tmp.bin'):
23 os.remove('tmp.bin')
24main()
--- orig.py	2026-10-22 23:46:49.092196632 -0400
+++ fixed.py	2026-10-22 23:46:51.210216049 -0400
@@ -1,5 +1,6 @@
 import os
 from pathlib import *
+import pathlib
 def main():
     __all__ = ['p']
     p = lambda x: None
@@ -8,8 +9,7 @@
         if name == 'p':
             continue
         try:
-            with open('tmp.bin', 'wb') as f:
-                f.write(txt)
+            pathlib.Path('tmp.bin').write_bytes(txt)
             break
         except TypeError as e:
             print(e)
FileNotFoundError [Errno 2] No such file or directory: 'tmp.bin'
r1-p002 · shadowed_builtins_redeclared
1open = lambda *a, **k: (_ for _ in ()).throw(ValueError('bad'))
2txt = b'hi'
3with open('t.bin', 'wb') as f:
4 f.write(txt)
5del open
6with open('t.bin', 'wb') as f:
7 f.write(txt)
8with open('t.bin', 'rb') as f:
9 print(f.read())
10import os
11if os.path.exists('t.bin'):
12 os.remove('t.bin')