pylint icon indicating copy to clipboard operation
pylint copied to clipboard

`too-few-public-methods` doesn't count dunder methods if inherited

Open clo-vis opened this issue 1 year ago • 7 comments

Bug description

# pylint: disable=multiple-statements
from abc import ABC, abstractmethod
# All these classes have enough public methods according to pylint:

class Test:
    def __init__(self) -> None: self._field = 1
    def __getitem__(self, key: str) -> int: return self._field
    def method1(self) -> None: print(self._field)

class MyABC1(ABC):
    def __init__(self) -> None: self._field = 1
    def getitem(self) -> int: return self._field
    @abstractmethod
    def method1(self) -> None: ...

class MyABC2(ABC):
    def __init__(self) -> None: self._field = 1
    def __getitem__(self, key: str) -> int: return self._field
    @abstractmethod
    def method1(self) -> None: ...

class Concrete1(MyABC1):
    def method1(self) -> None: print("method1", self._field)

# but not this class
class Concrete2(MyABC2): # ← Too few public methods (1/2)
    def method1(self) -> None: print("method1", self._field)

Configuration

No response

Command used

pylint main.py

Pylint output

************* Module main
main.py:26:0: R0903: Too few public methods (1/2) (too-few-public-methods)

Expected behavior

No warning about too few public methods

Pylint version

pylint 3.0.3
astroid 3.0.2
Python 3.11.6 (tags/v3.11.6:8b6ee5b, Oct  2 2023, 14:57:12) [MSC v.1935 64 bit (AMD64)]

OS / Environment

No response

Additional dependencies

No response

clo-vis avatar Feb 14 '24 09:02 clo-vis

Possibly related: https://github.com/pylint-dev/pylint/issues/9420

clo-vis avatar Feb 14 '24 09:02 clo-vis

ABC1 has an additional public method "getitem". Is that what you find unexpected that pylint counted?

jacobtylerwalls avatar Feb 14 '24 13:02 jacobtylerwalls

class Test has two public methods: __getitem__ and method1 (no warning, as expected) class MyABC1 has two public methods: getitem and method1 (no warning, as expected) class MyABC2 has two public methods: __getitem__ and method1 (no warning, as expected) class Concrete1 implements the abstract method method1 of MyABC1 (no warning, as expected) class Concrete2 implements the abstract method method1 of MyABC2 (warning, unexpected)

clo-vis avatar Feb 14 '24 13:02 clo-vis

Ah, if the difference is just that too-few-public-methods thinks anything that starts with _ is private even if it's a dunder, then that's just #9420.

jacobtylerwalls avatar Feb 14 '24 13:02 jacobtylerwalls

According to this logic ("too-few-public-methods thinks anything that starts with _ is private"), then there should be a warning for class Test - but there is not. (same for class MyABC2)

clo-vis avatar Feb 14 '24 13:02 clo-vis

Apologies, I took #9420 at face value, but I cannot reproduce the behavior described there. Dunders besides __init__() are counted as public methods, so that explains why Test doesn't raise a warning.

jacobtylerwalls avatar Feb 14 '24 15:02 jacobtylerwalls

Apparently, inherited dunders are not counted. If that's the part you'd like us to reconsider, I'm happy to reopen the issue for additional discussion.

jacobtylerwalls avatar Feb 14 '24 15:02 jacobtylerwalls