Skip to content

PLE0302 has false positives and false negatives #16217

@dscorbett

Description

@dscorbett

Description

unexpected-special-method-signature (PLE0302) has false positives and false negatives in Ruff 0.9.6.

The following methods are not special in Python 3, so they have no expected signatures. They are already caught by bad-dunder-method-name (PLW3201).

$ cat >ple0302_fp.py <<'# EOF'
class C:
    def __cmp__(self): ...
    def __div__(self): ...
    def __nonzero__(self, x): ...
    def __unicode__(self, x): ...
# EOF

$ ruff --isolated check --preview --select PLE0302,PLW3201 ple0302_fp.py --output-format concise
ple0302_fp.py:2:9: PLE0302 The special method `__cmp__` expects 2 parameters, 1 was given
ple0302_fp.py:2:9: PLW3201 Dunder method `__cmp__` has no special meaning in Python 3
ple0302_fp.py:3:9: PLE0302 The special method `__div__` expects 2 parameters, 1 was given
ple0302_fp.py:3:9: PLW3201 Dunder method `__div__` has no special meaning in Python 3
ple0302_fp.py:4:9: PLE0302 The special method `__nonzero__` expects 1 parameter, 2 were given
ple0302_fp.py:4:9: PLW3201 Dunder method `__nonzero__` has no special meaning in Python 3
ple0302_fp.py:5:9: PLE0302 The special method `__unicode__` expects 1 parameter, 2 were given
ple0302_fp.py:5:9: PLW3201 Dunder method `__unicode__` has no special meaning in Python 3
Found 8 errors.

The following methods are special in Python 3 but PLE0302 does not check them.

$ cat >ple0302_fn_1.py <<'# EOF'
class C:
    def __next__(self, x): ...  # should have 1 parameter
    def __buffer__(self): ...  # should have 2 parameters
    def __class_getitem__(self): ...  # should have 2 parameters
    def __mro_entries__(self): ...  # should have 2 parameters
    def __release_buffer__(self): ...  # should have 2 parameters
    def __subclasshook__(self): ...  # should have 2 parameters
# EOF

$ ruff --isolated check --select PLE0302 ple0302_fn_1.py
All checks passed!

Python only passes arguments to dunder methods positionally, so it is fine to declare some of the parameters as positional-only. PLE0302 ignores method definitions with positional-only parameters, causing false negatives.

$ cat >ple0302_fn_2.py <<'# EOF'
class C:
    def __setattr__(self, /, name): ...  # should have 3 parameters
    def __setitem__(self, key, /, value, extra_value): ...  # should have 3 parameters
# EOF

$ ruff --isolated check --select PLE0302 ple0302_fn_2.py
All checks passed!

$ sed 's:/, ::' ple0302_fn_2.py | ruff --isolated check --select PLE0302 - --output-format concise
-:2:9: PLE0302 The special method `__setattr__` expects 3 parameters, 2 were given
-:3:9: PLE0302 The special method `__setitem__` expects 3 parameters, 4 were given
Found 2 errors.

There are two special functions on modules, __dir__ and __getattr__, which PLE0302 doesn’t check. They might be out of scope for this rule, because it is documented to be for methods, but it would be a natural extension.

$ cat >ple0302_fn_3.py <<'# EOF'
def __dir__(self): ...  # should have 0 parameters
def __getattr__(): ...  # should have 1 parameter
# EOF

$ ruff --isolated check --select PLE0302 ple0302_fn_3.py
All checks passed!

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghelp wantedContributions especially welcome

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions