ruff/crates/ruff_python_semantic/src
cake-monotone 96dd1b1587
Consider `__new__` methods as special function type for enforcing class method or static method rules (#13305)
## Summary

`__new__` methods are technically static methods, with `cls` as their
first argument. However, Ruff currently classifies them as classmethod,
which causes two issues:

- It conveys incorrect information, leading to confusion. For example,
in cases like ARG003, `__new__` is explicitly treated as a classmethod.
- Future rules that should apply to staticmethod may not be applied
correctly due to this misclassification.

Motivated by this, the current PR makes the following adjustments:

1. Introduces `FunctionType::NewMethod` as an enum variant, since, for
the purposes of lint rules, `__new__` sometimes behaves like a static
method and other times like a class method. This is an internal change.

2. The following rule behaviors and messages are totally unchanged:
- [too-many-arguments
(PLR0913)](https://docs.astral.sh/ruff/rules/too-many-arguments/#too-many-arguments-plr0913)
- [too-many-positional-arguments
(PLR0917)](https://docs.astral.sh/ruff/rules/too-many-positional-arguments/#too-many-positional-arguments-plr0917)
3. The following rule behaviors are unchanged, but the messages have
been changed for correctness to use "`__new__` method" instead of "class
method":
- [self-or-cls-assignment
(PLW0642)](https://docs.astral.sh/ruff/rules/self-or-cls-assignment/#self-or-cls-assignment-plw0642)
4. The following rules are changed _unconditionally_ (not gated behind
preview) because their current behavior is an honest bug: it just isn't
true that `__new__` is a class method, and it _is_ true that `__new__`
is a static method:
- [unused-class-method-argument
(ARG003)](https://docs.astral.sh/ruff/rules/unused-class-method-argument/#unused-class-method-argument-arg003)
no longer applies to `__new__`
- [unused-static-method-argument
(ARG004)](https://docs.astral.sh/ruff/rules/unused-static-method-argument/#unused-static-method-argument-arg004)
now applies to `__new__`
5. The only changes which differ based on `preview` are the following:
- [invalid-first-argument-name-for-class-method
(N804)](https://docs.astral.sh/ruff/rules/invalid-first-argument-name-for-class-method/#invalid-first-argument-name-for-class-method-n804):
This is _skipped_ when `preview` is _enabled_. When `preview` is
_disabled_, the rule is the same but the _message_ has been modified to
say "`__new__` method" instead of "class method".
- [bad-staticmethod-argument
(PLW0211)](https://docs.astral.sh/ruff/rules/bad-staticmethod-argument/#bad-staticmethod-argument-plw0211):
When `preview` is enabled, this now applies to `__new__`.

Closes #13154

---------

Co-authored-by: dylwil3 <dylwil3@gmail.com>
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2025-02-16 14:12:25 -06:00
..
analyze Consider `__new__` methods as special function type for enforcing class method or static method rules (#13305) 2025-02-16 14:12:25 -06:00
model Upgrade Rust toolchain to 1.83 (#14677) 2024-11-29 12:05:05 +00:00
binding.rs [`ruff`] Fix false positive on global keyword (`RUF052`) (#15235) 2025-01-14 08:36:40 +01:00
branches.rs Add branch detection to the semantic model (#6694) 2023-08-19 21:28:17 +00:00
context.rs Remove separate `ReferenceContext` enum (#4631) 2023-05-24 15:12:38 +00:00
definition.rs Make setting and retrieving pydocstyle settings less tedious (#12582) 2024-07-31 10:39:33 +01:00
globals.rs Refine SemanticModel lifetime bounds (#10221) 2024-03-04 09:21:13 +01:00
imports.rs Config error only when `flake8-import-conventions` alias conflicts with `isort.required-imports` bound name (#15918) 2025-02-04 17:05:35 -06:00
lib.rs Move required import parsing out of lint rule (#12536) 2024-07-26 13:35:45 -04:00
model.rs Recognize all symbols named `TYPE_CHECKING` for `in_type_checking_block` (#15719) 2025-02-06 14:45:12 +01:00
nodes.rs Remove customizable reference enum names (#15647) 2025-01-21 13:46:31 -05:00
reference.rs [`ruff`] Avoid emitting `assignment-in-assert` when all references to the assigned variable are themselves inside `assert`s (`RUF018`) (#14661) 2024-11-29 13:36:59 +00:00
scope.rs Upgrade Rust toolchain to 1.83 (#14677) 2024-11-29 12:05:05 +00:00
star_import.rs Make ImportFrom level just a u32 (#11170) 2024-04-26 20:38:35 -06:00