Skip to content

E1520 recommends an invalid combination of @singledispatch and @staticmethod #9531

Closed
@AlexWaygood

Description

@AlexWaygood

Bug description

Hi from Ruff!

We recently received a bug report at Ruff stating that our reimplementation of E1520 was recommending an invalid combination of @functools.singledispatch and @staticmethod. For example, this code runs fine, but ruff's PLE1520 rule was telling the issue reporter that they should use @singledispatch here instead of @singledispatchmethod. If you do so, the code raises an exception at runtime, as @staticmethod is a descriptor, and @singledispatch isn't designed to be stacked on top of descriptor instances (that's what @singledispatchmethod is for). The Python docs also state that @singledispatchmethod should be used for static methods: https://docs.python.org/3/library/functools.html#functools.singledispatchmethod.

from functools import singledispatch, singledispatchmethod

class Foo:
    @singledispatchmethod
    @staticmethod
    def bar(value):
        raise NotImplementedError() 

    @bar.register
    @staticmethod
    def _(value: int) -> int:
        return 42 * value

    def method(self) -> int:
        return self.bar(2)

print(Foo().method())

After investigating the bug, we decided to change our PLE1520 rule so that it no longer complained about @singledispatchmethod on top of @staticmethod. It looks like pylint has the same incorrect behaviour here in the original PLE1520 rule, though, so I thought I'd open an issue to give you a heads-up as well!

In case it's helpful, here's the fix that was contributed to Ruff to fix the bug: astral-sh/ruff#10637. The fix also involved some small changes to PLE1519 (E1519 at pylint) as well as PLE1520 (E1520 at pylint).

Command used

pylint demo.py

Pylint output

************* Module demo
demo.py:7:35: C0303: Trailing whitespace (trailing-whitespace)
demo.py:1:0: C0114: Missing module docstring (missing-module-docstring)
demo.py:3:0: C0115: Missing class docstring (missing-class-docstring)
demo.py:6:4: C0116: Missing function or method docstring (missing-function-docstring)
demo.py:6:4: C0104: Disallowed name "bar" (disallowed-name)
demo.py:4:5: E1520: singledispatchmethod decorator should not be used with functions, use singledispatch instead. (singledispatchmethod-function)
demo.py:9:5: E1520: singledispatchmethod decorator should not be used with functions, use singledispatch instead. (singledispatchmethod-function)
demo.py:14:4: C0116: Missing function or method docstring (missing-function-docstring)
demo.py:1:0: W0611: Unused singledispatch imported from functools (unused-import)

------------------------------------------------------------------
Your code has been rated at 0.00/10 (previous run: 0.00/10, +0.00)

Expected behavior

************* Module demo
demo.py:7:35: C0303: Trailing whitespace (trailing-whitespace)
demo.py:1:0: C0114: Missing module docstring (missing-module-docstring)
demo.py:3:0: C0115: Missing class docstring (missing-class-docstring)
demo.py:6:4: C0116: Missing function or method docstring (missing-function-docstring)
demo.py:6:4: C0104: Disallowed name "bar" (disallowed-name)
demo.py:14:4: C0116: Missing function or method docstring (missing-function-docstring)
demo.py:1:0: W0611: Unused singledispatch imported from functools (unused-import)

------------------------------------------------------------------
Your code has been rated at 10.00/10 (previous run: 0.00/10, +0.00)

Pylint version

pylint 3.1.0
astroid 3.1.0
Python 3.12.2 (main, Feb 15 2024, 19:30:27) [Clang 15.0.0 (clang-1500.1.0.2.5)]

OS / Environment

MacOS; Python 3.12.2

Additional dependencies

None

Metadata

Metadata

Assignees

No one assigned

    Labels

    False Positive 🦟A message is emitted but nothing is wrong with the codeHelp wanted 🙏Outside help would be appreciated, good for new contributorsNeeds PRThis issue is accepted, sufficiently specified and now needs an implementation

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions