Skip to content

[ruff] Add incorrect-decorator-order (RUF074)#23461

Merged
ntBre merged 14 commits into
astral-sh:mainfrom
anishgirianish:ruf071-incorrect-decorator-order
May 19, 2026
Merged

[ruff] Add incorrect-decorator-order (RUF074)#23461
ntBre merged 14 commits into
astral-sh:mainfrom
anishgirianish:ruf071-incorrect-decorator-order

Conversation

@anishgirianish
Copy link
Copy Markdown
Contributor

@anishgirianish anishgirianish commented Feb 21, 2026

Summary

Implements detection of incorrect decorator ordering on functions and methods (RUF071).

Decorators are applied bottom-up, so certain stdlib decorator combinations cause runtime errors or silent wrong behavior when placed in the wrong order. For example, @abstractmethod above @property results in AttributeError: __isabstractmethod__.

Detects known-bad pairs involving:

  • abc.abstractmethod (+ deprecated abstractclassmethod, abstractstaticmethod, abstractproperty)
  • builtins.property, builtins.classmethod, builtins.staticmethod
  • contextlib.contextmanager, contextlib.asynccontextmanager
  • functools.cache, functools.cached_property, functools.lru_cache

Test Plan

cargo nextest run -p ruff_linter -E 'test(preview_rules::rule_incorrectdecoratororder)'

Fixture covers:

  • All known-bad pairs (core + functools)
  • Qualified imports (abc.abstractmethod, functools.lru_cache)
  • Deprecated abc forms (abstractproperty, abstractclassmethod, abstractstaticmethod)
  • Decorator call forms (@lru_cache(), @lru_cache(maxsize=128))
  • Interleaved unknown decorators
  • Multiple violations on the same function
  • Correct orderings, single decorators, unrelated decorators (no false positives)

Closes #6697

@anishgirianish anishgirianish changed the title [ruff] Implement incorrect-decorator-order (RUF071) [ruff] Add RUF071 incorrect-decorator-order Feb 21, 2026
@astral-sh-bot
Copy link
Copy Markdown

astral-sh-bot Bot commented Feb 21, 2026

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

ℹ️ ecosystem check detected linter changes. (+2 -0 violations, +0 -0 fixes in 2 projects; 54 projects unchanged)

python/typeshed (+1 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --no-fix --output-format concise --preview --select E,F,FA,I,PYI,RUF,UP,W

+ stubs/yt-dlp/yt_dlp/utils/_jsruntime.pyi:16:5: RUF074 `@functools.cached_property` should be placed after `@abstractmethod`

pdm-project/pdm (+1 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --no-fix --output-format concise --preview

+ src/pdm/project/lockfile/base.py:60:5: RUF074 `@functools.cached_property` should be placed after `@abstractmethod`

Changes by rule (1 rules affected)

code total + violation - violation + fix - fix
RUF074 2 2 0 0 0

@ntBre ntBre added rule Implementing or modifying a lint rule preview Related to preview mode features labels Feb 23, 2026
@ntBre
Copy link
Copy Markdown
Contributor

ntBre commented Feb 23, 2026

Could you check the ecosystem results? cached_property and abstractmethod seem to be working okay in that order, so I don't think we should emit a diagnostic.

@anishgirianish
Copy link
Copy Markdown
Contributor Author

Could you check the ecosystem results? cached_property and abstractmethod seem to be working okay in that order, so I don't think we should emit a diagnostic.

sure checking now thanks

Copy link
Copy Markdown
Contributor

@ntBre ntBre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this looks reasonable to me overall (although I still need to go through all the test cases). I mainly had a question about the multi-decorator case and a nit about Display.

Comment thread crates/ruff_linter/src/rules/ruff/rules/incorrect_decorator_order.rs Outdated
Comment thread crates/ruff_linter/src/rules/ruff/rules/incorrect_decorator_order.rs Outdated
@anishgirianish
Copy link
Copy Markdown
Contributor Author

Hi @ntBre @amyreese, I've addressed the review comments. Would love another look whenever you have time. Thanks so much!

Copy link
Copy Markdown
Contributor

@ntBre ntBre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Just a couple more questions about @property.setter and possible references for the chosen pairs.

Comment thread crates/ruff_linter/src/rules/ruff/rules/incorrect_decorator_order.rs Outdated
@anishgirianish
Copy link
Copy Markdown
Contributor Author

@ntBre @amyreese Addressed both comments and pushed the changes. Ready for another look whenever you get a chance!

@anishgirianish anishgirianish requested a review from ntBre February 28, 2026 19:10
@anishgirianish anishgirianish force-pushed the ruf071-incorrect-decorator-order branch from 7b99afd to ced38ec Compare March 14, 2026 08:37
Bump IncorrectDecoratorOrder from RUF071 to RUF072 since RUF071
was taken by OsPathCommonprefix upstream.
@anishgirianish anishgirianish force-pushed the ruf071-incorrect-decorator-order branch from ced38ec to 41d5164 Compare March 14, 2026 08:45
@anishgirianish anishgirianish changed the title [ruff] Add RUF071 incorrect-decorator-order [ruff] Add RUF072 incorrect-decorator-order Mar 14, 2026
…corator-order

# Conflicts:
#	crates/ruff_linter/resources/test/fixtures/ruff/RUF072.py
#	crates/ruff_linter/src/codes.rs
#	crates/ruff_linter/src/rules/ruff/mod.rs
#	crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__preview__RUF072_RUF072.py.snap
#	ruff.schema.json
@anishgirianish anishgirianish changed the title [ruff] Add RUF072 incorrect-decorator-order [ruff] Add RUF074 incorrect-decorator-order Apr 6, 2026
@anishgirianish
Copy link
Copy Markdown
Contributor Author

Hi @ntBre @amyreese would like to request you for your re-review on this one, when ever you get a chance. Thank you

@ntBre ntBre self-assigned this Apr 14, 2026
@ntBre
Copy link
Copy Markdown
Contributor

ntBre commented Apr 14, 2026

Sorry for the delay! The past couple of weeks have been quite busy, but this is back in my queue. I'll try to get to it this week :)

@ntBre ntBre removed the request for review from amyreese May 18, 2026 18:28
Copy link
Copy Markdown
Contributor

@ntBre ntBre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! And apologies again for the delay.

I took a closer look at some of the flagged pairs today, and I don't think we're quite aligned with CPython. Unfortunately, it also looks like some of the errors depend on the Python version being tested.

I think what would be really helpful is if you could prepare a series of code snippets that test every pair of decorators the rule lints against, like the examples I shared in my inline comments, that way we can easily compare against CPython itself. I think a REPL session would actually be a nice way to share this because we should be able to use doctest to run this against multiple Python versions.

The test fixture is close to this, it's just hard to use directly because pasting the whole thing into the REPL stops at the first error.

Comment thread crates/ruff_linter/src/rules/ruff/rules/incorrect_decorator_order.rs Outdated
Comment thread crates/ruff_linter/src/rules/ruff/rules/incorrect_decorator_order.rs Outdated
Comment thread crates/ruff_linter/src/rules/ruff/mod.rs Outdated
@anishgirianish
Copy link
Copy Markdown
Contributor Author

anishgirianish commented May 19, 2026

Thanks @ntBre! Put together a REPL recording (attached as ruf074_repl.txt). It's an 81-test doctest session covering every pair the rule lints against, both orderings, plus the false-positive aliases and the version-dependent pair. Verified passing on 3.10, 3.11, 3.12, 3.13, and 3.14:

python -m doctest -o ELLIPSIS ruf074_repl.txt

I have addressed all the feedback and fixes that were spotted during REPL session. I have update the pr with the changes.

ruf074_repl.txt

Would like to request you for your re-review whenever you get a chance. Thank you so much.

@anishgirianish anishgirianish requested a review from ntBre May 19, 2026 12:59
Copy link
Copy Markdown
Contributor

@ntBre ntBre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, this is awesome! The doctests are really polished and very, very helpful.

I just had one last suggestion for handling the version-dependent error, which I think might be doable, but this is otherwise ready to go.

Comment thread crates/ruff_linter/src/rules/ruff/rules/incorrect_decorator_order.rs Outdated
@anishgirianish
Copy link
Copy Markdown
Contributor Author

Hi @ntBre thank you so much for the re-review, I have addressed the recent feedback and updated the pr. Would like to request you for your another look whenever you get a chance

thank you

Copy link
Copy Markdown
Contributor

@ntBre ntBre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@ntBre ntBre changed the title [ruff] Add RUF074 incorrect-decorator-order [ruff] Add incorrect-decorator-order (RUF074) May 19, 2026
@ntBre
Copy link
Copy Markdown
Contributor

ntBre commented May 19, 2026

Nice, it looks like two ecosystem diagnostics are the cached_property and abstractmethod cases that don't cause runtime errors but silently change behavior.

@ntBre ntBre merged commit 51a7c2e into astral-sh:main May 19, 2026
45 checks passed
anishgirianish added a commit to anishgirianish/ruff that referenced this pull request May 20, 2026
Resolve conflicts caused by upstream landing RUF074
(`incorrect-decorator-order`, astral-sh#23461). Renumber the in-progress
`FallibleContextManager` rule from RUF074 to RUF075:

- codes.rs: keep `IncorrectDecoratorOrder` at 074 (landed), add
  `FallibleContextManager` at 075
- mod.rs: keep both `test_case` entries; FallibleContextManager now
  references `RUF075.py`
- Rename fixture: HEAD's `RUF074.py` content moves to new `RUF075.py`
  with `# RUF074` annotations updated to `# RUF075`
- Rename snapshot: HEAD's snapshot becomes `RUF075_RUF075.py.snap` with
  `RUF074` references rewritten to `RUF075`
- fallible_context_manager.rs: rule-id comment updated to RUF075
- ruff.schema.json regenerated via `cargo dev generate-all`
thejchap pushed a commit to thejchap/ruff that referenced this pull request May 23, 2026
## Summary

Implements detection of incorrect decorator ordering on functions and
methods (RUF071).
Decorators are applied bottom-up, so certain stdlib decorator
combinations cause runtime errors or silent wrong behavior when placed
in the wrong order. For example, `@abstractmethod` above `@property`
results in `AttributeError: __isabstractmethod__`.

Detects known-bad pairs involving:
- `abc.abstractmethod` (+ deprecated `abstractclassmethod`,
`abstractstaticmethod`, `abstractproperty`)
- `builtins.property`, `builtins.classmethod`, `builtins.staticmethod`
- `contextlib.contextmanager`, `contextlib.asynccontextmanager`
- `functools.cache`, `functools.cached_property`, `functools.lru_cache`

## Test Plan

`cargo nextest run -p ruff_linter -E
'test(preview_rules::rule_incorrectdecoratororder)'`

 Fixture covers: 
- All known-bad pairs (core + functools)
- Qualified imports (`abc.abstractmethod`, `functools.lru_cache`)
- Deprecated abc forms (`abstractproperty`, `abstractclassmethod`,
`abstractstaticmethod`)
- Decorator call forms (`@lru_cache()`, `@lru_cache(maxsize=128)`)
- Interleaved unknown decorators
- Multiple violations on the same function
- Correct orderings, single decorators, unrelated decorators (no false
positives)

Closes astral-sh#6697
anishgirianish added a commit to anishgirianish/ruff that referenced this pull request May 28, 2026
## Summary

Implements detection of incorrect decorator ordering on functions and
methods (RUF071).
Decorators are applied bottom-up, so certain stdlib decorator
combinations cause runtime errors or silent wrong behavior when placed
in the wrong order. For example, `@abstractmethod` above `@property`
results in `AttributeError: __isabstractmethod__`.

Detects known-bad pairs involving:
- `abc.abstractmethod` (+ deprecated `abstractclassmethod`,
`abstractstaticmethod`, `abstractproperty`)
- `builtins.property`, `builtins.classmethod`, `builtins.staticmethod`
- `contextlib.contextmanager`, `contextlib.asynccontextmanager`
- `functools.cache`, `functools.cached_property`, `functools.lru_cache`

## Test Plan

`cargo nextest run -p ruff_linter -E
'test(preview_rules::rule_incorrectdecoratororder)'`

 Fixture covers: 
- All known-bad pairs (core + functools)
- Qualified imports (`abc.abstractmethod`, `functools.lru_cache`)
- Deprecated abc forms (`abstractproperty`, `abstractclassmethod`,
`abstractstaticmethod`)
- Decorator call forms (`@lru_cache()`, `@lru_cache(maxsize=128)`)
- Interleaved unknown decorators
- Multiple violations on the same function
- Correct orderings, single decorators, unrelated decorators (no false
positives)

Closes astral-sh#6697
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

preview Related to preview mode features rule Implementing or modifying a lint rule

Projects

None yet

Development

Successfully merging this pull request may close these issues.

new rule - detect when decorators are in the wrong order

3 participants