Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make module deprecation checks reusable to plugins #4086

Closed
matusvalo opened this issue Feb 12, 2021 · 1 comment · Fixed by #4225
Closed

Make module deprecation checks reusable to plugins #4086

matusvalo opened this issue Feb 12, 2021 · 1 comment · Fixed by #4225
Labels
Checkers Related to a checker Enhancement ✨ Improvement to a component

Comments

@matusvalo
Copy link
Collaborator

Is your feature request related to a problem? Please describe

Imports checker contains checks for deprecated modules:

pylint/pylint/checkers/imports.py

https://github.com/PyCQA/pylint/blob/d825c21e18de5618cfcacea0fd818efa80a6b0fe/pylint/checkers/imports.py#L229-L233

Unfortunately, there is no easy way how it can be simply reused to add support for deprecation checks in pylint plugins.

Describe the solution you'd like

Extend solution proposed in #4049 and #4051 to support also deprecated modules

Additional context

The final plugin can look like as follows:

import astroid

from pylint.checkers import BaseChecker, DeprecatedMixin, utils
from pylint.interfaces import IAstroidChecker


class DeprecationChecker(BaseChecker, DeprecatedMixin):
    __implements__ = (IAstroidChecker,)
    name = "deprecated"
    msgs = {
        "W0002": (
            "Using deprecated method %s()",
            "deprecated-method",
            "The method is marked as deprecated and will be removed in "
            "the future.",
        ),
        "W0003": (
            "Using deprecated module %s()",
            "deprecated-module",
            "The module is marked as deprecated and will be removed in "
            "the future.",
        ),

    }

    def visit_call(self, node):
        try:
            for inferred in node.func.infer():
                # Calling entry point for deprecation check logic.
                self.check_deprecated_method(node, inferred)
        except astroid.InferenceError:
            return

    def visit_import(self, node):
        """triggered when an import statement is seen"""
        names = [name for name, _ in node.names]
        for name in names:
            self._check_deprecated_module(node, name)

    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):
        return {'mymodule.deprecated_function', 'mymodule.MyClass.deprecated_method'}

    def deprecated_modules(self):
        return {'deprecated_module1', 'deprecated_module2'}


def register(linter):
    linter.register_checker(DeprecationChecker(linter))
@matusvalo
Copy link
Collaborator Author

Another possible improvement can be that Mixin class will also contain predefined implementation of visit_* methods (which can be of course overwritten) with default logic. Hence, the straightforward usage of the mixin will be even more simple just defining following class:

import astroid

from pylint.checkers import BaseChecker, DeprecatedMixin, utils
from pylint.interfaces import IAstroidChecker


class DeprecationChecker(BaseChecker, DeprecatedMixin):
    __implements__ = (IAstroidChecker,)
    name = "deprecated"
    msgs = {
        "W0002": (
            "Using deprecated method %s()",
            "deprecated-method",
            "The method is marked as deprecated and will be removed in "
            "the future.",
        ),
        "W0003": (
            "Using deprecated module %s()",
            "deprecated-module",
            "The module is marked as deprecated and will be removed in "
            "the future.",
        ),
    }

    def deprecated_methods(self):
        return {'mymodule.deprecated_function', 'mymodule.MyClass.deprecated_method'}

    def deprecated_modules(self):
        return {'deprecated_module1', 'deprecated_module2'}


def register(linter):
    linter.register_checker(DeprecationChecker(linter))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Checkers Related to a checker Enhancement ✨ Improvement to a component
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants