diff options
author | Matus Valo <matusvalo@users.noreply.github.com> | 2021-03-17 23:03:18 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-17 23:03:18 +0100 |
commit | cdfc8374b1b0ee88af0463bdbe58299186244d53 (patch) | |
tree | 113c71198672978be5efb41e892f34412ba8810e | |
parent | f94b6d5ce5f22299d253d97eda1bf9e10045ce89 (diff) | |
download | pylint-git-cdfc8374b1b0ee88af0463bdbe58299186244d53.tar.gz |
Move deprecated module checker to DeprecatedMixin (#4225)
* Move deprecated module checker to DeprecatedMixin
Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | pylint/checkers/deprecated.py | 33 | ||||
-rw-r--r-- | pylint/checkers/imports.py | 22 | ||||
-rw-r--r-- | tests/checkers/unittest_deprecated.py | 37 |
4 files changed, 84 insertions, 12 deletions
@@ -15,6 +15,10 @@ Release date: TBA alternative to ``extension-pkg-whitelist`` and the message ``blacklisted-name`` is now emitted as ``disallowed-name``. The previous names are accepted to maintain backward compatibility. +* Move deprecated checker to ``DeprecatedMixin`` + + Closes #4086 + What's New in Pylint 2.7.3? =========================== diff --git a/pylint/checkers/deprecated.py b/pylint/checkers/deprecated.py index 9a4f636e4..8aaa02506 100644 --- a/pylint/checkers/deprecated.py +++ b/pylint/checkers/deprecated.py @@ -32,6 +32,11 @@ class DeprecatedMixin: "deprecated-argument", "The argument is marked as deprecated and will be removed in the future.", ), + "W0402": ( + "Uses of a deprecated module %r", + "deprecated-module", + "A module marked as deprecated is imported.", + ), } @utils.check_messages( @@ -47,6 +52,18 @@ class DeprecatedMixin: except astroid.InferenceError: pass + @utils.check_messages("deprecated-module") + def visit_import(self, node): + """triggered when an import statement is seen""" + for name in (name for name, _ in node.names): + self.check_deprecated_module(node, name) + + @utils.check_messages("deprecated-module") + def visit_importfrom(self, node): + """triggered when a from statement is seen""" + basename = node.modname + self.check_deprecated_module(node, basename) + def deprecated_methods(self) -> Container[str]: """Callback returning the deprecated methods/functions. @@ -85,6 +102,22 @@ class DeprecatedMixin: # pylint: disable=unused-argument return () + def deprecated_modules(self) -> Iterable: + """Callback returning the deprecated modules. + + Returns: + collections.abc.Container of deprecated module names. + """ + # pylint: disable=no-self-use + return () + + def check_deprecated_module(self, node, mod_path): + """Checks if the module is deprecated""" + + for mod_name in self.deprecated_modules(): + if mod_path == mod_name or mod_path.startswith(mod_name + "."): + self.add_message("deprecated-module", node=node, args=mod_path) + def check_deprecated_method(self, node, inferred): """Executes the checker for the given node. This method should be called from the checker implementing this mixin. diff --git a/pylint/checkers/imports.py b/pylint/checkers/imports.py index 82ff07448..ba14108c4 100644 --- a/pylint/checkers/imports.py +++ b/pylint/checkers/imports.py @@ -49,7 +49,7 @@ import astroid from astroid import modutils from astroid.decorators import cached -from pylint.checkers import BaseChecker +from pylint.checkers import BaseChecker, DeprecatedMixin from pylint.checkers.utils import ( check_messages, is_from_fallback_block, @@ -292,7 +292,7 @@ DEFAULT_KNOWN_THIRD_PARTY = ("enchant",) DEFAULT_PREFERRED_MODULES = () -class ImportsChecker(BaseChecker): +class ImportsChecker(DeprecatedMixin, BaseChecker): """checks for * external modules dependencies * relative / wildcard imports @@ -306,13 +306,13 @@ class ImportsChecker(BaseChecker): name = "imports" msgs = MSGS priority = -2 - deprecated_modules = ("optparse", "tkinter.tix") + default_deprecated_modules = ("optparse", "tkinter.tix") options = ( ( "deprecated-modules", { - "default": deprecated_modules, + "default": default_deprecated_modules, "type": "csv", "metavar": "<modules>", "help": "Deprecated modules which should not be used," @@ -487,6 +487,10 @@ class ImportsChecker(BaseChecker): for cycle in get_cycles(graph, vertices=vertices): self.add_message("cyclic-import", args=" -> ".join(cycle)) + def deprecated_modules(self): + """Callback returning the deprecated modules.""" + return self.config.deprecated_modules + @check_messages(*MSGS) def visit_import(self, node): """triggered when an import statement is seen""" @@ -499,7 +503,7 @@ class ImportsChecker(BaseChecker): self.add_message("multiple-imports", args=", ".join(names), node=node) for name in names: - self._check_deprecated_module(node, name) + self.check_deprecated_module(node, name) self._check_preferred_module(node, name) imported_module = self._get_imported_module(node, name) if isinstance(node.parent, astroid.Module): @@ -521,7 +525,7 @@ class ImportsChecker(BaseChecker): self._check_import_as_rename(node) self._check_misplaced_future(node) - self._check_deprecated_module(node, basename) + self.check_deprecated_module(node, basename) self._check_preferred_module(node, basename) self._check_wildcard_imports(node, imported_module) self._check_same_line_imports(node) @@ -832,12 +836,6 @@ class ImportsChecker(BaseChecker): if not self.linter.is_message_enabled("cyclic-import", line=node.lineno): self._excluded_edges[context_name].add(importedmodname) - def _check_deprecated_module(self, node, mod_path): - """check if the module is deprecated""" - for mod_name in self.config.deprecated_modules: - if mod_path == mod_name or mod_path.startswith(mod_name + "."): - self.add_message("deprecated-module", node=node, args=mod_path) - def _check_preferred_module(self, node, mod_path): """check if the module has a preferred replacement""" if mod_path in self.preferred_modules: diff --git a/tests/checkers/unittest_deprecated.py b/tests/checkers/unittest_deprecated.py index f7e8c1309..f9b45cd6d 100644 --- a/tests/checkers/unittest_deprecated.py +++ b/tests/checkers/unittest_deprecated.py @@ -12,6 +12,9 @@ class _DeprecatedChecker(DeprecatedMixin, BaseChecker): def deprecated_methods(self): return {"deprecated_func", ".Deprecated.deprecated_method"} + def deprecated_modules(self): + return {"deprecated_module"} + def deprecated_arguments(self, method): if method == "myfunction1": # def myfunction1(arg1, deprecated_arg1='spam') @@ -355,3 +358,37 @@ class TestDeprecatedChecker(CheckerTestCase): ), ): self.checker.visit_call(node) + + def test_deprecated_module(self): + # Tests detecting deprecated module + node = astroid.extract_node( + """ + import deprecated_module + """ + ) + with self.assertAddsMessages( + Message( + msg_id="deprecated-module", + args="deprecated_module", + node=node, + confidence=UNDEFINED, + ) + ): + self.checker.visit_import(node) + + def test_deprecated_module_from(self): + # Tests detecting deprecated module + node = astroid.extract_node( + """ + from deprecated_module import myfunction + """ + ) + with self.assertAddsMessages( + Message( + msg_id="deprecated-module", + args="deprecated_module", + node=node, + confidence=UNDEFINED, + ) + ): + self.checker.visit_importfrom(node) |