fixhunt

ruff UP009

labelled unknown
Runs / 2026-10-17T21-13-56-323Z-xzoc-ruff-UP009ruff 0.17.12026-10-17 21:13 UTC8 programs × 2 round(s)16 programs, 13 fired, 13 fixed, 1 findings, 0 rejectedmodel cost $0.01

Analysis Nemotron 3 Super

Flags redundant UTF-8 encoding declarations at the top of Python files.

Fix: Removes the UTF-8 encoding declaration line if it is the first or second line (after a shebang) and matches the pattern for UTF-8 (case-insensitive, with or without underscores, and optional spacing).

8 hazards
  • Removing a UTF-8 declaration in a file that actually contains non-UTF-8 encoded bytes would cause a SyntaxError when the file is parsed, as Python would default to UTF-8 decoding.
  • If the file relies on the encoding declaration to specify UTF-8 but is saved in a different encoding (e.g., Latin-1), removing the declaration changes how non-ASCII literals are interpreted, potentially altering string values.
  • The rewrite may remove a comment that is functionally part of a multi-line comment block if the encoding line is mistaken for comment content, though this is unlikely given its specific form.
  • In tools or environments that scan for encoding declarations beyond the first two lines (non-standard), removing it could break those tools even if Python 3+ ignores it.
  • If the encoding line is indented or has leading whitespace (invalid per PEP 263 but sometimes tolerated), the autofix might not trigger, but if it did, removing it could leave meaningless whitespace or affect line-number-sensitive debugging.
  • If the file uses a shebang and the encoding line is the second line, removing it shifts the shebang to line 1 and content to line 2, which is semantically identical but may affect tools that expect the encoding line at a fixed position.
  • In a concatenated script built from multiple files, removing the encoding declaration from a fragment could cause misinterpretation if the fragment is evaluated in isolation before concatenation.
  • If the encoding declaration is duplicated or malformed (e.g., '# coding: utf-8;;'), the autofix may not fire or may partially remove it, leaving syntax errors or strange remnants.

Findings

programoraclelabeljudgestatussummary
r2-p006fix-changes-behaviorlabelled safereal · lowrelatedRemoving the encoding declaration shifts all subsequent line numbers up by one, which changes the value returned by inspect.currentframe().f_lineno. The rule d…

Programs

idresulttitlehazard
r1-p001fix okClass Attributes vs Instance Properties with Side EffectsRemoving encoding line may shift line numbers affecting decorators like @property that rely on source location for introspection or error messages.
r1-p002fix okAsync Generator and Await Ordering HazardLine shift from encoding removal may confuse debuggers or tools mapping async generator state to source, altering perceived yield points.
r1-p003fix okMutable Default Argument Aliasing After RewriteIf encoding line removal shifts line numbers, and the function is recreated via exec or eval using line-based slicing, default arg binding may be re-evaluated unexpectedly.
r1-p004fix ok prediction offIndented Encoding Line Whitespace HazardIf tool incorrectly removes indented encoding line, it leaves trailing whitespace or alters indentation-sensitive logic like continued statements.
r1-p005fix okRuntime Type Annotation Evaluation with Typing-Only ImportsLine number shift from encoding removal may break inspect.getsource() used by typing extensions or dataclasses during runtime evaluation of annotations.
r1-p006fix okNon-Standard Tool Scanning Beyond First Two LinesSome linters or editors look for encoding declarations past line 2; removing it breaks them even if Python ignores it.
r1-p007fix okContext Manager with Write But No CloseIf encoding line is removed and a custom context manager uses line numbers for logging or tracing, removing it may misalign log entries with source.
r1-p008fix okDict Ordering, Duplicate Keys, and Hash/Eq InteractionsLine number shift may affect __eq__ or __hash__ implementations that use frame inspection or source traces, altering dict key equivalence.
r2-p001silent prediction offLatin-1 file saved as UTF-8 but declared Latin-1If the file relies on the encoding declaration to specify UTF-8 but is saved in a different encoding (e.g., Latin-1), removing the declaration changes how non-ASCII literals are interpreted, potential
r2-p002silent prediction offNon-standard scanner expecting encoding beyond line 2In tools or environments that scan for encoding declarations beyond the first two lines (non-standard), removing it could break those tools even if Python 3+ ignores it.
r2-p003silentEncoding line inside multi-line comment blockThe rewrite may remove a comment that is functionally part of a multi-line comment block if the encoding line is mistaken for comment content, though this is unlikely given its specific form.
r2-p004fix okAsync generator line-number sensitivity in debug infoasync def/await ordering, async generators
r2-p005fix okWalrus in comprehension late-binding hazard after line shiftwalrus, comprehensions scoping, late binding in closures and lambdas
r2-p006fix-changes-behaviorNon-file context manager relying on line numbers for IDcontext managers that are not files, objects with write() but no close()
r2-p007fix okBinary write truncation hazard after line-number shiftfile modes and truncation, partial writes, non-str data passed to write
r2-p008fix okDict ordering and hash sensitivity to line-number-based frozensetdict ordering, duplicate keys, __hash__/__eq__ overrides, sets

Sources

r1-p001 · Class Attributes vs Instance Properties with Side Effects
1# -*- coding: utf-8 -*-
2class A:
3 x = 1
4 @property
5 def y(self):
6 return self.__class__.x + 1
7try:
8 print(A().y)
9except Exception as e:
10 print(type(e).__name__, str(e))
--- orig.py	2026-10-17 17:14:04.815518111 -0400
+++ fixed.py	2026-10-17 17:14:04.995502389 -0400
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 class A:
     x = 1
     @property
2
r1-p002 · Async Generator and Await Ordering Hazard
1# -*- coding: utf-8 -*-
2async def gen():
3 yield 1
4 await asyncio.sleep(0)
5async def main():
6 g = gen()
7 print(await g.__anext__())
8import asyncio
9asyncio.run(main())
--- orig.py	2026-10-17 17:14:05.101493146 -0400
+++ fixed.py	2026-10-17 17:14:05.403466817 -0400
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 async def gen():
     yield 1
     await asyncio.sleep(0)
1
r1-p003 · Mutable Default Argument Aliasing After Rewrite
1# -*- coding: utf-8 -*-
2def f(a=[]):
3 a.append(1)
4 return a
5print(f())
6print(f())
--- orig.py	2026-10-17 17:14:05.582451211 -0400
+++ fixed.py	2026-10-17 17:14:05.757435954 -0400
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 def f(a=[]):
     a.append(1)
     return a
[1]
[1, 1]
r1-p004 · Indented Encoding Line Whitespace Hazard
1 # coding: utf-8
2x = 1
3print(x)
--- orig.py	2026-10-17 17:14:05.867426364 -0400
+++ fixed.py	2026-10-17 17:14:06.040411288 -0400
@@ -1,3 +1,2 @@
-    # coding: utf-8
 x = 1
 print(x)
1
r1-p005 · Runtime Type Annotation Evaluation with Typing-Only Imports
1# -*- coding: utf-8 -*-
2from typing import List
3class C:
4 x: List[int] = []
5 def __init__(self):
6 self.x.append(len(self.x))
7print(C().x)
--- orig.py	2026-10-17 17:14:06.144402237 -0400
+++ fixed.py	2026-10-17 17:14:06.337385442 -0400
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 from typing import List
 class C:
     x: List[int] = []
[0]
r1-p006 · Non-Standard Tool Scanning Beyond First Two Lines
1# coding: utf-8
2"""
3This is a module docstring.
4It spans multiple lines.
5"""
6print('encoding declared')
--- orig.py	2026-10-17 17:14:06.456375087 -0400
+++ fixed.py	2026-10-17 17:14:06.627360206 -0400
@@ -1,4 +1,3 @@
-# coding: utf-8
 """
 This is a module docstring.
 It spans multiple lines.
encoding declared
r1-p007 · Context Manager with Write But No Close
1# -*- coding: utf-8 -*-
2class LogWriter:
3 def __enter__(self):
4 print('enter')
5 return self
6 def write(self, msg):
7 print(f'log: {msg}')
8 def __exit__(self, *exc):
9 print('exit')
10with LogWriter() as w:
11 w.write('test')
--- orig.py	2026-10-17 17:14:06.725351678 -0400
+++ fixed.py	2026-10-17 17:14:06.900336449 -0400
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 class LogWriter:
     def __enter__(self):
         print('enter')
enter
log: test
exit
r1-p008 · Dict Ordering, Duplicate Keys, and Hash/Eq Interactions
1# -*- coding: utf-8 -*-
2class Key:
3 def __init__(self, v):
4 self.v = v
5 def __eq__(self, other):
6 return isinstance(other, Key) and self.v == other.v
7 def __hash__(self):
8 return hash(self.v)
9d = {Key(1): 'a', Key(1): 'b'}
10print(len(d))
--- orig.py	2026-10-17 17:14:07.006327225 -0400
+++ fixed.py	2026-10-17 17:14:07.175312546 -0400
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 class Key:
     def __init__(self, v):
         self.v = v
1
r2-p001 · Latin-1 file saved as UTF-8 but declared Latin-1
1# -*- coding: latin-1 -*-
2print(repr('\xe9'))
'é'
r2-p002 · Non-standard scanner expecting encoding beyond line 2
1"""Module docstring
2Second line."""
3# coding: utf-8
4print(b'\xc3\xa9'.decode('utf-8'))
é
r2-p003 · Encoding line inside multi-line comment block
1'''
2This is a multi-line comment.
3# -*- coding: utf-8 -*-
4Still in comment.
5'''
6print('safe')
safe
r2-p004 · Async generator line-number sensitivity in debug info
1# -*- coding: utf-8 -*-
2async def gen():
3 yield 1
4 await asyncio.sleep(0)
5async def main():
6 async for v in gen():
7 print(v)
8asyncio.run(main())
--- orig.py	2026-10-17 17:14:12.395860974 -0400
+++ fixed.py	2026-10-17 17:14:12.787827239 -0400
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 async def gen():
     yield 1
     await asyncio.sleep(0)
r2-p005 · Walrus in comprehension late-binding hazard after line shift
1# coding: utf-8
2ls = []
3for i in range(2):
4 ls.append(lambda: (j := i))
5print([f() for f in ls])
--- orig.py	2026-10-17 17:14:13.023806933 -0400
+++ fixed.py	2026-10-17 17:14:13.185793017 -0400
@@ -1,4 +1,3 @@
-# coding: utf-8
 ls = []
 for i in range(2):
     ls.append(lambda: (j := i))
[1, 1]
r2-p006 · Non-file context manager relying on line numbers for ID
1# -*- coding: utf-8 -*-
2class DebugCM:
3 def __enter__(self):
4 import inspect
5 self.line = inspect.currentframe().f_lineno
6 return self
7 def __exit__(self, *args):
8 pass
9 def write(self, s):
10 print(s)
11with DebugCM() as cm:
12 cm.write(f'line {cm.line}')
--- orig.py	2026-10-17 17:14:13.288784170 -0400
+++ fixed.py	2026-10-17 17:14:13.502765787 -0400
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 class DebugCM:
     def __enter__(self):
         import inspect
line 5
r2-p007 · Binary write truncation hazard after line-number shift
1# coding: utf-8
2with open('test.bin', 'wb') as f:
3 f.write(b'hazard')
4 f.truncate(5)
5with open('test.bin', 'rb') as f:
6 print(f.read())
7import os
8os.remove('test.bin')
--- orig.py	2026-10-17 17:14:13.622755480 -0400
+++ fixed.py	2026-10-17 17:14:13.788741221 -0400
@@ -1,4 +1,3 @@
-# coding: utf-8
 with open('test.bin', 'wb') as f:
     f.write(b'hazard')
     f.truncate(5)
b'hazar'
r2-p008 · Dict ordering and hash sensitivity to line-number-based frozenset
1# -*- coding: utf-8 -*-
2class LineKey:
3 def __init__(self):
4 import inspect
5 self.line = inspect.currentframe().f_lineno
6 def __hash__(self):
7 return hash(self.line)
8 def __eq__(self, other):
9 return isinstance(other, LineKey) and self.line == other.line
10k1 = LineKey()
11k2 = LineKey()
12d = {k1: 'first', k2: 'second'}
13print(len(d))
--- orig.py	2026-10-17 17:14:13.894732115 -0400
+++ fixed.py	2026-10-17 17:14:14.114713236 -0400
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 class LineKey:
     def __init__(self):
         import inspect
1