mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 18:58:04 +00:00
[pylint
] Fix false positives, add missing methods, and support positional-only parameters (PLE0302
) (#16263)
## Summary Resolves 3/4 requests in #16217: - ✅ Remove not special methods: `__cmp__`, `__div__`, `__nonzero__`, and `__unicode__`. - ✅ Add special methods: `__next__`, `__buffer__`, `__class_getitem__`, `__mro_entries__`, `__release_buffer__`, and `__subclasshook__`. - ✅ Support positional-only arguments. - ❌ Add support for module functions `__dir__` and `__getattr__`. As mentioned in the issue the check is scoped for methods rather than module functions. I am hesitant to expand the scope of this check without a discussion. ## Test Plan - Manually confirmed each example file from the issue functioned as expected. - Ran cargo nextest to ensure `unexpected_special_method_signature` test still passed. Fixes #16217.
This commit is contained in:
parent
b3c5932fda
commit
b9b094869a
3 changed files with 119 additions and 14 deletions
|
@ -68,8 +68,44 @@ class TestClass:
|
|||
def __eq__(self, **kwargs): # ignore **kwargs
|
||||
...
|
||||
|
||||
def __eq__(self, /, other=42): # ignore positional-only args
|
||||
def __eq__(self, /, other=42): # support positional-only args
|
||||
...
|
||||
|
||||
def __eq__(self, *, other=42): # ignore positional-only args
|
||||
def __eq__(self, *, other=42): # ignore keyword-only args
|
||||
...
|
||||
|
||||
def __cmp__(self): # #16217 assert non-special method is skipped, expects 2 parameters
|
||||
...
|
||||
|
||||
def __div__(self): # #16217 assert non-special method is skipped, expects 2 parameters
|
||||
...
|
||||
|
||||
def __nonzero__(self, x): # #16217 assert non-special method is skipped, expects 1 parameter
|
||||
...
|
||||
|
||||
def __unicode__(self, x): # #16217 assert non-special method is skipped, expects 1 parameter
|
||||
...
|
||||
|
||||
def __next__(self, x): # #16217 assert special method is linted, expects 1 parameter
|
||||
...
|
||||
|
||||
def __buffer__(self): # #16217 assert special method is linted, expects 2 parameters
|
||||
...
|
||||
|
||||
def __class_getitem__(self): # #16217 assert special method is linted, expects 2 parameters
|
||||
...
|
||||
|
||||
def __mro_entries__(self): # #16217 assert special method is linted, expects 2 parameters
|
||||
...
|
||||
|
||||
def __release_buffer__(self): # #16217 assert special method is linted, expects 2 parameters
|
||||
...
|
||||
|
||||
def __subclasshook__(self): # #16217 assert special method is linted, expects 2 parameters
|
||||
...
|
||||
|
||||
def __setattr__(self, /, name): # #16217 assert positional-only special method is linted, expects 3 parameters
|
||||
...
|
||||
|
||||
def __setitem__(self, key, /, value, extra_value): # #16217 assert positional-only special method is linted, expects 3 parameters
|
||||
...
|
|
@ -23,10 +23,8 @@ impl ExpectedParams {
|
|||
| "__neg__" | "__pos__" | "__abs__" | "__invert__" | "__complex__" | "__int__"
|
||||
| "__float__" | "__index__" | "__trunc__" | "__floor__" | "__ceil__" | "__enter__"
|
||||
| "__aenter__" | "__getnewargs_ex__" | "__getnewargs__" | "__getstate__"
|
||||
| "__reduce__" | "__copy__" | "__unicode__" | "__nonzero__" | "__await__"
|
||||
| "__aiter__" | "__anext__" | "__fspath__" | "__subclasses__" => {
|
||||
Some(ExpectedParams::Fixed(0))
|
||||
}
|
||||
| "__reduce__" | "__copy__" | "__await__" | "__aiter__" | "__anext__"
|
||||
| "__fspath__" | "__subclasses__" | "__next__" => Some(ExpectedParams::Fixed(0)),
|
||||
"__format__" | "__lt__" | "__le__" | "__eq__" | "__ne__" | "__gt__" | "__ge__"
|
||||
| "__getattr__" | "__getattribute__" | "__delattr__" | "__delete__"
|
||||
| "__instancecheck__" | "__subclasscheck__" | "__getitem__" | "__missing__"
|
||||
|
@ -37,8 +35,9 @@ impl ExpectedParams {
|
|||
| "__rpow__" | "__rlshift__" | "__rrshift__" | "__rand__" | "__rxor__" | "__ror__"
|
||||
| "__iadd__" | "__isub__" | "__imul__" | "__itruediv__" | "__ifloordiv__"
|
||||
| "__imod__" | "__ilshift__" | "__irshift__" | "__iand__" | "__ixor__" | "__ior__"
|
||||
| "__ipow__" | "__setstate__" | "__reduce_ex__" | "__deepcopy__" | "__cmp__"
|
||||
| "__matmul__" | "__rmatmul__" | "__imatmul__" | "__div__" => {
|
||||
| "__ipow__" | "__setstate__" | "__reduce_ex__" | "__deepcopy__" | "__matmul__"
|
||||
| "__rmatmul__" | "__imatmul__" | "__buffer__" | "__class_getitem__"
|
||||
| "__mro_entries__" | "__release_buffer__" | "__subclasshook__" => {
|
||||
Some(ExpectedParams::Fixed(1))
|
||||
}
|
||||
"__setattr__" | "__get__" | "__set__" | "__setitem__" | "__set_name__" => {
|
||||
|
@ -147,11 +146,8 @@ pub(crate) fn unexpected_special_method_signature(
|
|||
return;
|
||||
}
|
||||
|
||||
// Ignore methods with positional-only or keyword-only parameters, or variadic parameters.
|
||||
if !parameters.posonlyargs.is_empty()
|
||||
|| !parameters.kwonlyargs.is_empty()
|
||||
|| parameters.kwarg.is_some()
|
||||
{
|
||||
// Ignore methods with keyword-only parameters or variadic parameters.
|
||||
if !parameters.kwonlyargs.is_empty() || parameters.kwarg.is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -160,10 +156,11 @@ pub(crate) fn unexpected_special_method_signature(
|
|||
return;
|
||||
}
|
||||
|
||||
let actual_params = parameters.args.len();
|
||||
let actual_params = parameters.args.len() + parameters.posonlyargs.len();
|
||||
let mandatory_params = parameters
|
||||
.args
|
||||
.iter()
|
||||
.chain(parameters.posonlyargs.iter())
|
||||
.filter(|arg| arg.default.is_none())
|
||||
.count();
|
||||
|
||||
|
|
|
@ -71,3 +71,75 @@ unexpected_special_method_signature.py:65:9: PLE0302 The special method `__round
|
|||
| ^^^^^^^^^ PLE0302
|
||||
66 | ...
|
||||
|
|
||||
|
||||
unexpected_special_method_signature.py:89:9: PLE0302 The special method `__next__` expects 1 parameter, 2 were given
|
||||
|
|
||||
87 | ...
|
||||
88 |
|
||||
89 | def __next__(self, x): # #16217 assert special method is linted, expects 1 parameter
|
||||
| ^^^^^^^^ PLE0302
|
||||
90 | ...
|
||||
|
|
||||
|
||||
unexpected_special_method_signature.py:92:9: PLE0302 The special method `__buffer__` expects 2 parameters, 1 was given
|
||||
|
|
||||
90 | ...
|
||||
91 |
|
||||
92 | def __buffer__(self): # #16217 assert special method is linted, expects 2 parameters
|
||||
| ^^^^^^^^^^ PLE0302
|
||||
93 | ...
|
||||
|
|
||||
|
||||
unexpected_special_method_signature.py:95:9: PLE0302 The special method `__class_getitem__` expects 2 parameters, 1 was given
|
||||
|
|
||||
93 | ...
|
||||
94 |
|
||||
95 | def __class_getitem__(self): # #16217 assert special method is linted, expects 2 parameters
|
||||
| ^^^^^^^^^^^^^^^^^ PLE0302
|
||||
96 | ...
|
||||
|
|
||||
|
||||
unexpected_special_method_signature.py:98:9: PLE0302 The special method `__mro_entries__` expects 2 parameters, 1 was given
|
||||
|
|
||||
96 | ...
|
||||
97 |
|
||||
98 | def __mro_entries__(self): # #16217 assert special method is linted, expects 2 parameters
|
||||
| ^^^^^^^^^^^^^^^ PLE0302
|
||||
99 | ...
|
||||
|
|
||||
|
||||
unexpected_special_method_signature.py:101:9: PLE0302 The special method `__release_buffer__` expects 2 parameters, 1 was given
|
||||
|
|
||||
99 | ...
|
||||
100 |
|
||||
101 | def __release_buffer__(self): # #16217 assert special method is linted, expects 2 parameters
|
||||
| ^^^^^^^^^^^^^^^^^^ PLE0302
|
||||
102 | ...
|
||||
|
|
||||
|
||||
unexpected_special_method_signature.py:104:9: PLE0302 The special method `__subclasshook__` expects 2 parameters, 1 was given
|
||||
|
|
||||
102 | ...
|
||||
103 |
|
||||
104 | def __subclasshook__(self): # #16217 assert special method is linted, expects 2 parameters
|
||||
| ^^^^^^^^^^^^^^^^ PLE0302
|
||||
105 | ...
|
||||
|
|
||||
|
||||
unexpected_special_method_signature.py:107:9: PLE0302 The special method `__setattr__` expects 3 parameters, 2 were given
|
||||
|
|
||||
105 | ...
|
||||
106 |
|
||||
107 | def __setattr__(self, /, name): # #16217 assert positional-only special method is linted, expects 3 parameters
|
||||
| ^^^^^^^^^^^ PLE0302
|
||||
108 | ...
|
||||
|
|
||||
|
||||
unexpected_special_method_signature.py:110:9: PLE0302 The special method `__setitem__` expects 3 parameters, 4 were given
|
||||
|
|
||||
108 | ...
|
||||
109 |
|
||||
110 | def __setitem__(self, key, /, value, extra_value): # #16217 assert positional-only special method is linted, expects 3 parameters
|
||||
| ^^^^^^^^^^^ PLE0302
|
||||
111 | ...
|
||||
|
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue