Skip to content

Commit 96b3892

Browse files
Germandrummer92PCManticore
authored andcommitted
Add regexs for bad- and good-names to enable better white- or blacklisting (#3186)
To enable better handling of whitelisting/blacklisting names, we added two new config options: `good-names-rgxs` and `bad-names-rgxs`. They both are a comma-separated list of regexes, where the former is used for exempting names from name checking while the latter is used for always marking a name as blacklisted.
1 parent dd31060 commit 96b3892

File tree

6 files changed

+86
-2
lines changed

6 files changed

+86
-2
lines changed

CONTRIBUTORS.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,8 @@ contributors:
334334

335335
* Rémi Cardona: contributor
336336

337+
* Daniel Draper: contributor
338+
337339
* Gabriel R. Sezefredo: contributor
338340
- Fixed "exception-escape" false positive with generators
339341

doc/whatsnew/2.5.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,10 @@ Other Changes
3131
for example ``[tool.pylint.'MESSAGES CONTROL']``.
3232
These files can also be passed in on the command line.
3333

34+
* Add new good-names-rgx and bad-names-rgx to enable white-/blacklisting of regular expressions
35+
36+
To enable better handling of whitelisting/blacklisting names, we added two new config options: good-names-rgxs: a comma-
37+
separated list of regexes, that if a name matches will be exempt of naming-checking. bad-names-rgxs: a comma-
38+
separated list of regexes, that if a name matches will be always marked as a blacklisted name.
39+
3440
* Mutable ``collections.*`` are now flagged as dangerous defaults.

pylint/checkers/base.py

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1680,6 +1680,16 @@ class NameChecker(_BasicChecker):
16801680
" separated by a comma.",
16811681
},
16821682
),
1683+
(
1684+
"good-names-rgxs",
1685+
{
1686+
"default": "",
1687+
"type": "regexp_csv",
1688+
"metavar": "<names>",
1689+
"help": "Good variable names regexes, separated by a comma. If names match any regex,"
1690+
" they will always be accepted",
1691+
},
1692+
),
16831693
(
16841694
"bad-names",
16851695
{
@@ -1690,6 +1700,16 @@ class NameChecker(_BasicChecker):
16901700
"separated by a comma.",
16911701
},
16921702
),
1703+
(
1704+
"bad-names-rgxs",
1705+
{
1706+
"default": "",
1707+
"type": "regexp_csv",
1708+
"metavar": "<names>",
1709+
"help": "Bad variable names regexes, separated by a comma. If names match any regex,"
1710+
" they will always be refused",
1711+
},
1712+
),
16931713
(
16941714
"name-group",
16951715
{
@@ -1735,6 +1755,8 @@ def __init__(self, linter):
17351755
self._bad_names = {}
17361756
self._name_regexps = {}
17371757
self._name_hints = {}
1758+
self._good_names_rgxs_compiled = []
1759+
self._bad_names_rgxs_compiled = []
17381760

17391761
def open(self):
17401762
self.stats = self.linter.add_stats(
@@ -1756,6 +1778,12 @@ def open(self):
17561778
regexps, hints = self._create_naming_rules()
17571779
self._name_regexps = regexps
17581780
self._name_hints = hints
1781+
self._good_names_rgxs_compiled = [
1782+
re.compile(rgxp) for rgxp in self.config.good_names_rgxs
1783+
]
1784+
self._bad_names_rgxs_compiled = [
1785+
re.compile(rgxp) for rgxp in self.config.bad_names_rgxs
1786+
]
17591787

17601788
def _create_naming_rules(self):
17611789
regexps = {}
@@ -1894,6 +1922,16 @@ def _raise_name_warning(self, node, node_type, name, confidence):
18941922
self.add_message("invalid-name", node=node, args=args, confidence=confidence)
18951923
self.stats["badname_" + node_type] += 1
18961924

1925+
def _name_valid_due_to_whitelist(self, name: str) -> bool:
1926+
return name in self.config.good_names or any(
1927+
pattern.match(name) for pattern in self._good_names_rgxs_compiled
1928+
)
1929+
1930+
def _name_invalid_due_to_blacklist(self, name: str) -> bool:
1931+
return name in self.config.bad_names or any(
1932+
pattern.match(name) for pattern in self._bad_names_rgxs_compiled
1933+
)
1934+
18971935
def _check_name(self, node_type, name, node, confidence=interfaces.HIGH):
18981936
"""check for a name using the type's regexp"""
18991937

@@ -1908,9 +1946,9 @@ def _should_exempt_from_invalid_name(node):
19081946
clobbering, _ = utils.clobber_in_except(node)
19091947
if clobbering:
19101948
return
1911-
if name in self.config.good_names:
1949+
if self._name_valid_due_to_whitelist(name=name):
19121950
return
1913-
if name in self.config.bad_names:
1951+
if self._name_invalid_due_to_blacklist(name=name):
19141952
self.stats["badname_" + node_type] += 1
19151953
self.add_message("blacklisted-name", node=node, args=name)
19161954
return
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# pylint: disable=missing-docstring,too-few-public-methods
2+
__version__ = "1.0"
3+
ignored_SOME_CONSTANT = 42
4+
5+
explicit_bad_some_constant = 42 # [blacklisted-name]
6+
7+
snake_case_bad_SOME_CONSTANT = 42 # [invalid-name]
8+
9+
10+
class my_class:
11+
def __init__(self, arg_x):
12+
self._my_secret_x = arg_x
13+
14+
@property
15+
def my_public_x(self):
16+
return self._my_secret_x * 2
17+
18+
19+
def blacklisted_2_snake_case(): # [blacklisted-name]
20+
pass
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[BASIC]
2+
function-naming-style=snake_case
3+
const-naming-style=snake_case
4+
attr-naming-style=snake_case
5+
argument-naming-style=snake_case
6+
module-naming-style=snake_case
7+
method-naming-style=snake_case
8+
variable-naming-style=snake_case
9+
class-attribute-naming-style=snake_case
10+
inlinevar-naming-style=snake_case
11+
class-naming-style=snake_case
12+
13+
good-names-rgxs=ignored.*
14+
bad-names-rgxs=explicit.*,blacklisted.*
15+
include-naming-hint=yes
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
blacklisted-name:5::"Black listed name ""explicit_bad_some_constant"""
2+
invalid-name:7::"Constant name ""snake_case_bad_SOME_CONSTANT"" doesn't conform to snake_case naming style ('(([a-z_][a-z0-9_]*)|(__.*__))$' pattern)"
3+
blacklisted-name:19:blacklisted_2_snake_case:"Black listed name ""blacklisted_2_snake_case"""

0 commit comments

Comments
 (0)