summaryrefslogtreecommitdiff
path: root/pylint/interfaces.py
blob: 221084fab29f152125ef2147b83854c9b84dfd58 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE
# Copyright (c) https://github.com/PyCQA/pylint/blob/main/CONTRIBUTORS.txt

"""Interfaces for Pylint objects."""

from __future__ import annotations

import warnings
from tokenize import TokenInfo
from typing import TYPE_CHECKING, NamedTuple

from astroid import nodes

if TYPE_CHECKING:
    from pylint.checkers import BaseChecker
    from pylint.message import Message
    from pylint.reporters.ureports.nodes import Section

__all__ = (
    "IRawChecker",
    "IAstroidChecker",
    "ITokenChecker",
    "IReporter",
    "IChecker",
    "HIGH",
    "CONTROL_FLOW",
    "INFERENCE",
    "INFERENCE_FAILURE",
    "UNDEFINED",
    "CONFIDENCE_LEVELS",
    "CONFIDENCE_LEVEL_NAMES",
)


class Confidence(NamedTuple):
    name: str
    description: str


# Warning Certainties
HIGH = Confidence("HIGH", "Warning that is not based on inference result.")
CONTROL_FLOW = Confidence(
    "CONTROL_FLOW", "Warning based on assumptions about control flow."
)
INFERENCE = Confidence("INFERENCE", "Warning based on inference result.")
INFERENCE_FAILURE = Confidence(
    "INFERENCE_FAILURE", "Warning based on inference with failures."
)
UNDEFINED = Confidence("UNDEFINED", "Warning without any associated confidence level.")

CONFIDENCE_LEVELS = [HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE, UNDEFINED]
CONFIDENCE_LEVEL_NAMES = [i.name for i in CONFIDENCE_LEVELS]


class Interface:
    """Base class for interfaces."""

    def __init__(self) -> None:
        warnings.warn(
            "Interface and all of its subclasses have been deprecated "
            "and will be removed in pylint 3.0.",
            DeprecationWarning,
            stacklevel=2,
        )

    @classmethod
    def is_implemented_by(
        cls: type[Interface] | tuple[type[Interface], ...], instance: BaseChecker
    ) -> bool:
        with warnings.catch_warnings():
            warnings.filterwarnings("ignore", category=DeprecationWarning)
            return implements(instance, cls)


def implements(
    obj: BaseChecker,
    interface: type[Interface] | tuple[type[Interface], ...],
) -> bool:
    """Does the given object (maybe an instance or class) implement the interface."""
    # TODO: 3.0: Remove deprecated function
    warnings.warn(
        "implements has been deprecated in favour of using basic "
        "inheritance patterns without using __implements__.",
        DeprecationWarning,
        stacklevel=2,
    )
    implements_ = getattr(obj, "__implements__", ())
    if not isinstance(implements_, (list, tuple)):
        implements_ = (implements_,)
    return any(issubclass(i, interface) for i in implements_)


class IChecker(Interface):
    """Base interface, to be used only for sub interfaces definition."""

    def open(self) -> None:
        """Called before visiting project (i.e. set of modules)."""

    def close(self) -> None:
        """Called after visiting project (i.e. set of modules)."""


class IRawChecker(IChecker):
    """Interface for checker which need to parse the raw file."""

    def process_module(self, node: nodes.Module) -> None:
        """Process a module.

        The module's content is accessible via ``astroid.stream``
        """


class ITokenChecker(IChecker):
    """Interface for checkers that need access to the token list."""

    def process_tokens(self, tokens: list[TokenInfo]) -> None:
        """Process a module.

        Tokens is a list of all source code tokens in the file.
        """


class IAstroidChecker(IChecker):
    """Interface for checker which prefers receive events according to
    statement type.
    """


class IReporter(Interface):
    """Reporter collect messages and display results encapsulated in a layout."""

    def handle_message(self, msg: Message) -> None:
        """Handle the given message object."""

    def display_reports(self, layout: Section) -> None:
        """Display results encapsulated in the layout tree."""