fixhunt

ruff UP011

labelled unknown
Runs / 2026-10-17T21-15-05-200Z-bfsc-ruff-UP011ruff 0.17.12026-10-17 21:15 UTC8 programs × 2 round(s)16 programs, 11 fired, 11 fixed, 1 findings, 4 rejectedmodel cost $0.02

Analysis Nemotron 3 Super

Flags redundant parentheses when using @functools.lru_cache() without arguments.

Fix: Removes the trailing empty parentheses from @functools.lru_cache(), rewriting it as @functools.lru_cache while preserving spacing, imports, aliases, and surrounding decorators.

12 hazards
  • Rewriting @functools.lru_cache() inside a TYPE_CHECKING block may break type checking if the block is conditionally excluded at runtime but the linter assumes it is active.
  • If the decorator line contains a trailing comment after the parentheses, the fix may drop or misplace that comment during whitespace normalization.
  • When the decorator is applied to a class, removing parentheses could be misinterpreted if the class defines __call__ and the decorator is later invoked elsewhere in the module.
  • In code that manually inspects decorator syntax via ast or inspect, the absence of parentheses may alter the perceived call structure and break introspection logic.
  • If functools.lru_cache is shadowed by a local variable named lru_cache in an outer scope, the unqualified name after rewrite may resolve incorrectly.
  • When the decorator is used on a forward-referenced name in a string annotation context, the rewrite has no effect but may create inconsistency in mixed-style codebases.
  • If the line contains a line continuation character within the parentheses (e.g., due to formatting), removing them may break the syntactic validity of the statement.
  • In Python versions prior to 3.8, removing the parentheses would cause a SyntaxError because lru_cache could not be used as a bare decorator.
  • If the decorator is part of a macro-generated code block where the parentheses are significant for template matching, their removal may prevent correct expansion.
  • When the decorator appears in a stub (.pyi) file, some type checkers may expect the explicit call form for compatibility with older stubs, and the rewrite could trigger false positives.
  • If the decorator line is edited via a tool that relies on the presence of parentheses to delimit the decorator expression, subsequent edits may fail to parse correctly.
  • In rare cases where lru_cache is imported via a relative import or through a namespace package, the rewrite does not affect resolution but may obscure intent in code review.

Findings

programoraclelabeljudgestatussummary
r2-p005fix-changes-behaviorlabelled safeintrospection-only · lowrelatedThe program parses its own source code and inspects the AST node for the decorator, checking whether the decorator call has zero arguments. After the fix remov…

Programs

idresulttitlehazard
r1-p001invalidMacro-generated code dependence on parenthesesIf the decorator is part of a macro-generated code block where the parentheses are significant for template matching, their removal may prevent correct expansion.
r1-p002invalidTool-dependent parsing via parentheses delimitersIf the decorator line is edited via a tool that relies on the presence of parentheses to delimit the decorator expression, subsequent edits may fail to parse correctly.
r1-p003fix okWalrus/comprehension scoping interactionwalrus, comprehensions scoping, late binding in closures and lambdas
r1-p004silentComments/docstrings attachment preservationcomments and docstrings attached to the removed or moved code
r1-p005fix okAsync def/await ordering interactionasync def/await ordering, async generators
r1-p006fix okString formatting edge case interactionstring formatting edge cases: %, format, f-strings, repr vs str, nested quotes
r1-p007fix okShadowing by outer scope variableIf functools.lru_cache is shadowed by a local variable named lru_cache in an outer scope, the unqualified name after rewrite may resolve incorrectly.
r1-p008fix okBytes/str encoding and newline handlingbytes vs str, encoding and newline handling, text vs binary modes
r2-p001fix okFile mode truncation with LRU-cached writerfile modes and truncation, partial writes, non-str data passed to write
r2-p002fix okNumeric coercion with cached divisionint/float/bool coercion, Decimal, division and rounding
r2-p003invalidString formatting with nested quotes and reprstring formatting edge cases: %, format, f-strings, repr vs str, nested quotes
r2-p004fix okForward reference in string annotation with LRU cacheWhen the decorator is used on a forward-referenced name in a string annotation context, the rewrite has no effect but may create inconsistency in mixed-style codebases.
r2-p005fix-changes-behaviorAST introspection of decorator call structureIn code that manually inspects decorator syntax via ast or inspect, the absence of parentheses may alter the perceived call structure and break introspection logic.
r2-p006invalidBinary mode write with encoding-sensitive databytes vs str, encoding and newline handling, text vs binary modes
r2-p007fix okStub file compatibility simulationWhen the decorator appears in a stub (.pyi) file, some type checkers may expect the explicit call form for compatibility with older stubs, and the rewrite could trigger false positives.
r2-p008fix okRelative import and namespace package obscurityIn rare cases where lru_cache is imported via a relative import or through a namespace package, the rewrite does not affect resolution but may obscure intent in code review.

Sources

r1-p001 · Macro-generated code dependence on parentheses (generated program does not parse: Traceback (most recent call last):)
1import functools
2decorator = '@functools.lru_cache()'
3exec(decorator + '
4def f(): return 1')
5print(f())
r1-p002 · Tool-dependent parsing via parentheses delimiters (generated program does not parse: Traceback (most recent call last):)
1import functools
2source = '''def foo(): pass'''
3injected = source.replace('def', '@functools.lru_cache()
4def')
5exec(injected)
6print(foo.__wrapped__( )) if hasattr(foo, '__wrapped__') else print(type(foo))
r1-p003 · Walrus/comprehension scoping interaction
1from functools import lru_cache
2@lru_cache()
3def make_adder(n):
4 return lambda x: x + n
5f1 = make_adder(10)
6print(f1(5))
7# After fix: same behavior but tests sensitivity
--- orig.py	2026-10-17 17:15:27.585818711 -0400
+++ fixed.py	2026-10-17 17:15:27.759805675 -0400
@@ -1,5 +1,5 @@
 from functools import lru_cache
-@lru_cache()
+@lru_cache
 def make_adder(n):
   return lambda x: x + n
 f1 = make_adder(10)
15
r1-p004 · Comments/docstrings attachment preservation
1# This comment precedes the decorator
2def dummy():
3 """Docstring here."""
4 return 42
5print(dummy())
42
r1-p005 · Async def/await ordering interaction
1import functools
2@functools.lru_cache()
3async def fetch():
4 await _dummy()
5 return 99
6async def _dummy(): pass
7import asyncio
8result = asyncio.run(fetch())
9print(result)
--- orig.py	2026-10-17 17:15:27.992788219 -0400
+++ fixed.py	2026-10-17 17:15:28.291765859 -0400
@@ -1,5 +1,5 @@
 import functools
-@functools.lru_cache()
+@functools.lru_cache
 async def fetch():
   await _dummy()
   return 99
99
r1-p006 · String formatting edge case interaction
1from functools import lru_cache
2@lru_cache()
3def fmt(x):
4 return f'Value: {x!r}'
5print(fmt(42))
6print(fmt(42)) # cached
--- orig.py	2026-10-17 17:15:28.456753520 -0400
+++ fixed.py	2026-10-17 17:15:28.627740733 -0400
@@ -1,5 +1,5 @@
 from functools import lru_cache
-@lru_cache()
+@lru_cache
 def fmt(x):
   return f'Value: {x!r}'
 print(fmt(42))
Value: 42
Value: 42
r1-p007 · Shadowing by outer scope variable
1def outer():
2 lru_cache = lambda f: f # breaks lru_cache
3 from functools import lru_cache as real_lru
4 @real_lru()
5 def inner():
6 return 1
7 return inner()
8print(outer())
--- orig.py	2026-10-17 17:15:28.732732881 -0400
+++ fixed.py	2026-10-17 17:15:28.909719645 -0400
@@ -1,7 +1,7 @@
 def outer():
   lru_cache = lambda f: f  # breaks lru_cache
   from functools import lru_cache as real_lru
-  @real_lru()
+  @real_lru
   def inner():
     return 1
   return inner()
1
r1-p008 · Bytes/str encoding and newline handling
1import functools
2@functools.lru_cache()
3def read_file(path):
4 with open(path, 'r', encoding='utf-8') as f:
5 return f.read()
6with open('test.txt', 'w', encoding='utf-8') as f:
7 f.write('hello')
8print(read_file('test.txt'))
9import os
10os.remove('test.txt')
--- orig.py	2026-10-17 17:15:29.017711571 -0400
+++ fixed.py	2026-10-17 17:15:29.189698733 -0400
@@ -1,5 +1,5 @@
 import functools
-@functools.lru_cache()
+@functools.lru_cache
 def read_file(path):
   with open(path, 'r', encoding='utf-8') as f:
     return f.read()
hello
r2-p001 · File mode truncation with LRU-cached writer
1import functools
2@functools.lru_cache()
3def cached_write(data):
4 with open('tmp.bin', 'wb') as f:
5 if isinstance(data, float):
6 data = struct.pack('<d', data)
7 elif isinstance(data, bool):
8 data = b'\x01' if data else b'\x00'
9 f.write(data[:2]) # Truncate to 2 bytes
10 f.seek(0); return f.read()
11try:
12 result1 = cached_write(3.14)
13 result2 = cached_write(True)
14 print('float->bytes:', repr(result1))
15 print('bool->bytes:', repr(result2))
16except Exception as e:
17 print(type(e).__name__, str(e))
18finally:
19 import os; os.remove('tmp.bin') if os.path.exists('tmp.bin') else None
--- orig.py	2026-10-17 17:15:46.183449093 -0400
+++ fixed.py	2026-10-17 17:15:46.360436288 -0400
@@ -1,5 +1,5 @@
 import functools
-@functools.lru_cache()
+@functools.lru_cache
 def cached_write(data):
     with open('tmp.bin', 'wb') as f:
         if isinstance(data, float):
NameError name 'struct' is not defined
r2-p002 · Numeric coercion with cached division
1import functools, decimal
2@functools.lru_cache()
3def divide_cached(a, b):
4 return round(float(a) / float(b), 4)
5d = decimal.Decimal('10')
6print(divide_cached(d, 3)) # Decimal -> float via float()
7print(divide_cached(True, False)) # Bool division: True/False -> 1.0/0.0 -> ZeroDivisionError
8print(divide_cached(5, 2)) # Should hit cache on second call
9# Second call to same args should return cached value
10print(divide_cached(5, 2))
--- orig.py	2026-10-17 17:15:46.473428113 -0400
+++ fixed.py	2026-10-17 17:15:46.890397945 -0400
@@ -1,5 +1,5 @@
 import functools, decimal
-@functools.lru_cache()
+@functools.lru_cache
 def divide_cached(a, b):
     return round(float(a) / float(b), 4)
 d = decimal.Decimal('10')
3.3333
r2-p003 · String formatting with nested quotes and repr (generated program does not parse: Traceback (most recent call last):)
1import functools
2@functools.lru_cache()
3def fmt_cached(x):
4 s = str(x)
5 return f'{repr(s)} | {s!r} | %{s}
6'
7print(fmt_cached('hello\ world'))
8print(fmt_cached(42))
9# Second call should hit cache
10print(fmt_cached('hello\ world'))
r2-p004 · Forward reference in string annotation with LRU cache
1from __future__ import annotations
2import functools
3@functools.lru_cache()
4def process_data(value: 'DataProcessor') -> int:
5 return len(str(value))
6class DataProcessor:
7 def __init__(self, data):
8 self.data = data
9 def __str__(self):
10 return str(self.data)
11dp = DataProcessor('test123')
12print(process_data(dp))
13print(process_data(dp)) # Should be cached
--- orig.py	2026-10-17 17:15:47.252371789 -0400
+++ fixed.py	2026-10-17 17:15:47.417359874 -0400
@@ -1,6 +1,6 @@
 from __future__ import annotations
 import functools
-@functools.lru_cache()
+@functools.lru_cache
 def process_data(value: 'DataProcessor') -> int:
     return len(str(value))
 class DataProcessor:
7
7
r2-p005 · AST introspection of decorator call structure
1import functools, ast
2@functools.lru_cache()
3def cached_func(x):
4 return x * 2
5tree = ast.parse(open(__file__).read())
6for node in ast.walk(tree):
7 if isinstance(node, ast.FunctionDef) and node.name == 'cached_func':
8 for dec in node.decorator_list:
9 if isinstance(dec, ast.Call) and dec.func.attr == 'lru_cache':
10 print('Decorator is call:', len(dec.args) == 0 and len(dec.keywords) == 0)
11 elif isinstance(dec, ast.Attribute) and dec.attr == 'lru_cache':
12 print('Decorator is attribute only:', dec.attr)
13print('Result:', cached_func(5))
--- orig.py	2026-10-17 17:15:47.523352220 -0400
+++ fixed.py	2026-10-17 17:15:47.705339077 -0400
@@ -1,5 +1,5 @@
 import functools, ast
-@functools.lru_cache()
+@functools.lru_cache
 def cached_func(x):
     return x * 2
 tree = ast.parse(open(__file__).read())
Decorator is call: True
Result: 10
r2-p006 · Binary mode write with encoding-sensitive data (generated program does not parse: Traceback (most recent call last):)
1import functools, codecs
2@functools.lru_cache()
3def encode_and_write(text, encoding='utf-8'):
4 data = text.encode(encoding)
5 with open('tmp.dat', 'wb') as f:
6 f.write(data)
7 f.write(b'
8')
9 with open('tmp.dat', 'rb') as f:
10 return f.read().strip(b'
11')
12result1 = encode_and_write('café')
13result2 = encode_and_write('café') # Should hit cache
14print('First:', repr(result1))
15print('Second:', repr(result2))
16print('Equal:', result1 == result2)
17import os; os.remove('tmp.dat') if os.path.exists('tmp.dat') else None
r2-p007 · Stub file compatibility simulation
1# Simulate .pyi file behavior: type checker expects @functools.lru_cache()
2# But we are in .py file - rule will remove parentheses
3import functools
4@functools.lru_cache()
5def stubbed_func(x: int) -> str:
6 return str(x * 2)
7# If type checker sees @functools.lru_cache (no parens) in .pyi, it may error
8# We simulate by checking if the decorator form affects runtime
9print('Result:', stubbed_func(21))
10print('Cached:', stubbed_func.__wrapped__(21) if hasattr(stubbed_func, '__wrapped__') else 'no wrapper')
--- orig.py	2026-10-17 17:15:47.945321746 -0400
+++ fixed.py	2026-10-17 17:15:48.116309413 -0400
@@ -1,7 +1,7 @@
 # Simulate .pyi file behavior: type checker expects @functools.lru_cache()
 # But we are in .py file - rule will remove parentheses
 import functools
-@functools.lru_cache()
+@functools.lru_cache
 def stubbed_func(x: int) -> str:
     return str(x * 2)
 # If type checker sees @functools.lru_cache (no parens) in .pyi, it may error
Result: 42
Cached: 42
r2-p008 · Relative import and namespace package obscurity
1import sys, os
2sys.path.insert(0, os.path.dirname(__file__))
3try:
4 from .local_functools import lru_cache # Relative import simulation
5 @lru_cache()
6 def cached_local(x):
7 return x + 10
8except ImportError:
9 # Fallback: simulate namespace package by importing via package-like name
10 import functools as local_functools
11 @local_functools.lru_cache()
12 def cached_local(x):
13 return x + 10
14print(cached_local(5))
15print(cached_local(5)) # Cache hit
16# Cleanup
17if 'local_functools' in locals():
18 del local_functools
19if '.' in sys.path[0]:
20 sys.path.pop(0)
--- orig.py	2026-10-17 17:15:48.221301844 -0400
+++ fixed.py	2026-10-17 17:15:48.392289519 -0400
@@ -8,7 +8,7 @@
 except ImportError:
     # Fallback: simulate namespace package by importing via package-like name
     import functools as local_functools
-    @local_functools.lru_cache()
+    @local_functools.lru_cache
     def cached_local(x):
         return x + 10
 print(cached_local(5))
15
15