Skip to content

Commit 448485a

Browse files
Add configuration option exclude-too-few-public-methods (#5191)
Allow excluding classes based on their ancestors from the ``too-few-public-methods`` checker. Closes #3370 Signed-off-by: Mike Fiedler <[email protected]> Co-authored-by: Daniël van Noord <[email protected]>
1 parent 17d6926 commit 448485a

10 files changed

+75
-1
lines changed

CONTRIBUTORS.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,3 +562,5 @@ contributors:
562562
* Youngsoo Sung: contributor
563563

564564
* Arianna Yang: contributor
565+
566+
* Mike Fiedler (miketheman): contributor

ChangeLog

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,11 @@ Release date: TBA
107107
* Fix ``missing-function-docstring`` not being able to check ``__init__`` and other
108108
magic methods even if the ``no-docstring-rgx`` setting was set to do so
109109

110+
* Added configuration option ``exclude-too-few-public-methods`` to allow excluding
111+
classes from the ``min-public-methods`` checker.
112+
113+
Closes #3370
114+
110115

111116
What's New in Pylint 2.11.2?
112117
============================

doc/whatsnew/2.12.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ New checkers
4343

4444
Closes #4774
4545

46+
* Added configuration option ``exclude-too-few-public-methods`` to allow excluding
47+
classes from the ``min-public-methods`` checker.
48+
49+
Closes #3370
50+
4651

4752
Removed checkers
4853
================

pylint/checkers/design_analysis.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,16 @@ class MisdesignChecker(BaseChecker):
402402
"statement (see R0916).",
403403
},
404404
),
405+
(
406+
"exclude-too-few-public-methods",
407+
{
408+
"default": [],
409+
"type": "regexp_csv",
410+
"metavar": "<pattern>[,<pattern>...]",
411+
"help": "List of regular expressions of class ancestor names "
412+
"to ignore when counting public methods (see R0903)",
413+
},
414+
),
405415
)
406416

407417
def __init__(self, linter=None):
@@ -416,6 +426,9 @@ def open(self):
416426
self._returns = []
417427
self._branches = defaultdict(int)
418428
self._stmts = []
429+
self._exclude_too_few_public_methods = utils.get_global_option(
430+
self, "exclude-too-few-public-methods", default=[]
431+
)
419432

420433
def _inc_all_stmts(self, amount):
421434
for i, _ in enumerate(self._stmts):
@@ -472,6 +485,15 @@ def leave_classdef(self, node: nodes.ClassDef) -> None:
472485
args=(my_methods, self.config.max_public_methods),
473486
)
474487

488+
# Stop here if the class is excluded via configuration.
489+
if node.type == "class" and self._exclude_too_few_public_methods:
490+
for ancestor in node.ancestors():
491+
if any(
492+
pattern.match(ancestor.qname())
493+
for pattern in self._exclude_too_few_public_methods
494+
):
495+
return
496+
475497
# Stop here for exception, metaclass, interface classes and other
476498
# classes for which we don't need to count the methods.
477499
if node.type != "class" or _is_exempt_from_public_methods(node):

pylint/utils/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
"ignored-argument-names",
6060
"mixin-class-rgx",
6161
]
62-
GLOBAL_OPTION_PATTERN_LIST = Literal["ignore-paths"]
62+
GLOBAL_OPTION_PATTERN_LIST = Literal["exclude-too-few-public-methods", "ignore-paths"]
6363
GLOBAL_OPTION_TUPLE_INT = Literal["py-version"]
6464
GLOBAL_OPTION_NAMES = Union[
6565
GLOBAL_OPTION_BOOL,

pylintrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,9 @@ min-public-methods=2
350350
# Maximum number of public methods for a class (see R0904).
351351
max-public-methods=25
352352

353+
# List of regular expressions of class ancestor names to
354+
# ignore when counting public methods (see R0903).
355+
exclude-too-few-public-methods=
353356

354357
[CLASSES]
355358

tests/checkers/unittest_design.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
from pylint.checkers import design_analysis
1313
from pylint.testutils import CheckerTestCase, set_config
14+
from pylint.utils.utils import get_global_option
1415

1516

1617
class TestDesignChecker(CheckerTestCase):
@@ -42,3 +43,20 @@ class Eeee(Dddd):
4243
)
4344
with self.assertNoMessages():
4445
self.checker.visit_classdef(node)
46+
47+
@set_config(exclude_too_few_public_methods="toml.*")
48+
def test_exclude_too_few_methods_with_value(self) -> None:
49+
"""Test exclude-too-few-public-methods option with value"""
50+
options = get_global_option(self.checker, "exclude-too-few-public-methods")
51+
52+
assert any(i.match("toml") for i in options)
53+
assert any(i.match("toml.*") for i in options)
54+
assert any(i.match("toml.TomlEncoder") for i in options)
55+
56+
def test_ignore_paths_with_no_value(self) -> None:
57+
"""Test exclude-too-few-public-methods option with no value.
58+
Compare against actual list to see if validator works."""
59+
options = get_global_option(self.checker, "exclude-too-few-public-methods")
60+
61+
# pylint: disable-next=use-implicit-booleaness-not-comparison
62+
assert options == []
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# pylint: disable=missing-docstring
2+
from json import JSONEncoder
3+
4+
class Control: # [too-few-public-methods]
5+
...
6+
7+
8+
class MyJsonEncoder(JSONEncoder):
9+
...
10+
11+
class InheritedInModule(Control):
12+
"""This class inherits from a class that doesn't have enough mehods,
13+
and its parent is excluded via config, so it doesn't raise."""
14+
...
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[testoptions]
2+
min-public-methods=10 # to combat inherited methods
3+
4+
exclude-too-few-public-methods=json.*,^.*Control$
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
too-few-public-methods:4:0:Control:Too few public methods (0/10):HIGH

0 commit comments

Comments
 (0)