summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudiu Popa <pcmanticore@gmail.com>2019-09-26 08:20:36 +0200
committerClaudiu Popa <pcmanticore@gmail.com>2019-09-26 08:22:05 +0200
commit4d0fbec72d5c55591a9c35fa7a1bfdaa03be0e61 (patch)
treec6e724d554a4224851e3f5d0cc33def2a7922563
parent5f8084cfa046b937c6039a1194f935cae82438fb (diff)
downloadpylint-git-4d0fbec72d5c55591a9c35fa7a1bfdaa03be0e61.tar.gz
``ignored-modules`` can skip submodules. Close #3135
-rw-r--r--ChangeLog9
-rw-r--r--pylint/checkers/typecheck.py36
-rw-r--r--tests/unittest_checker_typecheck.py14
3 files changed, 49 insertions, 10 deletions
diff --git a/ChangeLog b/ChangeLog
index 8a03b7758..13966b9c3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,15 @@
Pylint's ChangeLog
------------------
+What's New in Pylint 2.4.2?
+===========================
+
+Release date: TBA
+
+
+* ``ignored-modules`` can skip submodules. Close #3135
+
+
What's New in Pylint 2.4.1?
===========================
diff --git a/pylint/checkers/typecheck.py b/pylint/checkers/typecheck.py
index e11902208..53014bc54 100644
--- a/pylint/checkers/typecheck.py
+++ b/pylint/checkers/typecheck.py
@@ -43,6 +43,7 @@ import re
import shlex
import sys
import types
+from collections import deque
from collections.abc import Sequence
from functools import singledispatch
@@ -99,7 +100,7 @@ def _flatten_container(iterable):
yield item
-def _is_owner_ignored(owner, name, ignored_classes, ignored_modules):
+def _is_owner_ignored(owner, attrname, ignored_classes, ignored_modules):
"""Check if the given owner should be ignored
This will verify if the owner's module is in *ignored_modules*
@@ -114,20 +115,37 @@ def _is_owner_ignored(owner, name, ignored_classes, ignored_modules):
ignored_modules = set(ignored_modules)
module_name = owner.root().name
module_qname = owner.root().qname()
- if any(
- module_name in ignored_modules
- or module_qname in ignored_modules
- or fnmatch.fnmatch(module_qname, ignore)
- for ignore in ignored_modules
- ):
- return True
+ for ignore in ignored_modules:
+ # Try to match the module name / fully qualified name directly
+ if module_qname in ignored_modules or module_name in ignored_modules:
+ return True
+
+ # Try to see if the ignores pattern match against the module name.
+ if fnmatch.fnmatch(module_qname, ignore):
+ return True
+
+ # Otherwise we might have a root module name being ignored,
+ # and the qualified owner has more levels of depth.
+ parts = deque(module_name.split("."))
+ current_module = ""
+
+ while parts:
+ part = parts.popleft()
+ if not current_module:
+ current_module = part
+ else:
+ current_module += ".{}".format(part)
+ if current_module in ignored_modules:
+ return True
+
+ # Match against ignored classes.
ignored_classes = set(ignored_classes)
if hasattr(owner, "qname"):
qname = owner.qname()
else:
qname = ""
- return any(ignore in (name, qname) for ignore in ignored_classes)
+ return any(ignore in (attrname, qname) for ignore in ignored_classes)
@singledispatch
diff --git a/tests/unittest_checker_typecheck.py b/tests/unittest_checker_typecheck.py
index 5c55c6710..f63680cdd 100644
--- a/tests/unittest_checker_typecheck.py
+++ b/tests/unittest_checker_typecheck.py
@@ -75,7 +75,7 @@ class TestTypeChecker(CheckerTestCase):
with self.assertNoMessages():
self.checker.visit_attribute(node)
- @set_config(ignored_classes=("xml.etree.",))
+ @set_config(ignored_modules=("xml.etree.",))
def test_ignored_modules_invalid_pattern(self):
node = astroid.extract_node(
"""
@@ -89,6 +89,18 @@ class TestTypeChecker(CheckerTestCase):
with self.assertAddsMessages(message):
self.checker.visit_attribute(node)
+ @set_config(ignored_modules=("xml",))
+ def test_ignored_modules_root_one_applies_as_well(self):
+ # Check that when a root module is completely ignored, submodules are skipped.
+ node = astroid.extract_node(
+ """
+ import xml
+ xml.etree.Lala
+ """
+ )
+ with self.assertNoMessages():
+ self.checker.visit_attribute(node)
+
@set_config(ignored_modules=("xml.etree*",))
def test_ignored_modules_patterns(self):
node = astroid.extract_node(