ruff UP011: fix changes program behavior
Hypothesis Nemotron 3 Super predicted to fire fired 1×
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.
Program
Output
Decorator is call: True
(no stdout) AttributeError: 'Attribute' object has no attribute 'args'
- fired
- 1 before · 0 after
- runs
- each version twice, same file name, no network
Judge Nemotron 3 Ultra advisory introspection-only · low
The 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 removes the parentheses, the AST node changes from a Call to an Attribute, so the introspection logic fails with an AttributeError. This is a change only in self-inspection of the rewritten source text, not in the runtime semantics of the decorated function.
Explanation Nemotron 3 Super unverified
The original decorator `@functools.lru_cache()` calls `lru_cache` with no arguments, returning a decorator function that wraps `cached_func`. After rewriting to `@functools.lru_cache`, the decorator becomes the raw function object itself, not its result; thus it does not wrap the function, leaving `cached_func` undecorated. During AST traversal, `dec` now refers to an `Attribute` node (`functools.lru_cache`) instead of a `Call` node, so accessing `.args` raises an AttributeError because attributes lack argument lists. This changes both behavior and output.
Reproduce
- file
prog.py(the before program)- minimized program
- r2-p005.py
- evidence sheet
- r2-p005.md
- regression fixture
- r2-p005.py the minimized program with a header stating the observed change, for the tool's test suite
python3 prog.py ruff check --preview --isolated --select UP011 --fix prog.py python3 prog.py
Upstream search GitHub issues Tavily Nemotron 3 Super + Ultra
UP011 fix · UP011 decorator parentheses removal · lru_cache empty call transformation · AST FunctionDef decorator args access
- related astral-sh/ruff/issues/1913 Same UP011 rule but different construct: that report is about `lru_cache(max_size=None)` → `lru_cache`, this one is about `lru_cache()` → `lru_cache`.
- related astral-sh/ruff/issues/827 Meta-issue tracking pyupgrade implementation including UP011, not the specific `lru_cache()` → `lru_cache` defect.
Details
- program
- AST introspection of decorator call structure
- hazard
- 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.
- oracle
stdout before: Decorator is call: True stdout after: exit 0 → 1 stderr before: (none) stderr after: AttributeError: 'Attribute' object has no attribute 'args'- run
- 2026-10-17T21-15-05-200Z-bfsc-ruff-UP011
generated program (13 lines) and the fix's diff
--- 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())
rule documentation given to the models
# lru-cache-without-parameters (UP011) Derived from the **pyupgrade** linter. Fix is always available. ## What it does Checks for unnecessary parentheses on `functools.lru_cache` decorators. ## Why is this bad? Since Python 3.8, `functools.lru_cache` can be used as a decorator without trailing parentheses, as long as no arguments are passed to it. ## Example ```python import functools @functools.lru_cache() def foo(): ... ``` Use instead: ```python import functools @functools.lru_cache def foo(): ... ``` ## Options - `target-version` ## References - [Python documentation: `@functools.lru_cache`](https://docs.python.org/3/library/functools.html#functools.lru_cache) - [Let lru_cache be used as a decorator with no arguments](https://github.com/python/cpython/issues/80953)