pylint-dev / pylint

It's not just a linter that annoys you!
https://pylint.readthedocs.io/en/latest/
GNU General Public License v2.0
5.32k stars 1.14k forks source link

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

Open clo-vis opened 9 months ago

clo-vis commented 9 months ago

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 commented 9 months ago

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

jacobtylerwalls commented 9 months ago

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

clo-vis commented 9 months ago

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)

jacobtylerwalls commented 9 months ago

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.

clo-vis commented 9 months ago

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)

jacobtylerwalls commented 9 months ago

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 commented 9 months ago

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.