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

[__implements__] Remove everything related to the rejected PEP245 #8404

Merged
merged 5 commits into from
Mar 8, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion doc/symilar.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ All files that shall be checked have to be passed in explicitly, e.g.::
==tests/data/suppliermodule_test.py:12
class Ancestor:
""" Ancestor method """
__implements__ = (Interface,)
cls_member = DoNothing()

def __init__(self, value):
Expand Down
9 changes: 9 additions & 0 deletions doc/whatsnew/fragments/8404.breaking
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Everything related to the ``__implements__`` construct was removed. It was based on PEP245
that was proposed in 2001 and rejected in 2006. It includes everything in ``pylint.interfaces``

``Checker`` should only inherit ``BaseChecker`` or any of the other checker types from ``pylint.checkers``.
``Reporter`` should only inherit ``BaseReporter``.

The capability from pyreverse to take it into account when generating diagrams was also removed.

Refs #8404
30 changes: 5 additions & 25 deletions pylint/checkers/base_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from pylint.config.arguments_provider import _ArgumentsProvider
from pylint.constants import _MSG_ORDER, MAIN_CHECKER_NAME, WarningScope
from pylint.exceptions import InvalidMessageError
from pylint.interfaces import Confidence, IRawChecker, ITokenChecker, implements
from pylint.interfaces import Confidence
from pylint.message.message_definition import MessageDefinition
from pylint.typing import (
ExtraMessageOptions,
Expand Down Expand Up @@ -47,18 +47,9 @@ class BaseChecker(_ArgumentsProvider):

def __init__(self, linter: PyLinter) -> None:
"""Checker instances should have the linter as argument."""
if getattr(self, "__implements__", None):
warnings.warn(
"Using the __implements__ inheritance pattern for BaseChecker is no "
"longer supported. Child classes should only inherit BaseChecker or any "
"of the other checker types from pylint.checkers.",
DeprecationWarning,
stacklevel=2,
)
if self.name is not None:
self.name = self.name.lower()
self.linter = linter

_ArgumentsProvider.__init__(self, linter)

def __gt__(self, other: Any) -> bool:
Expand Down Expand Up @@ -193,21 +184,10 @@ def check_consistency(self) -> None:
def create_message_definition_from_tuple(
self, msgid: str, msg_tuple: MessageDefinitionTuple
) -> MessageDefinition:
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
if isinstance(self, (BaseTokenChecker, BaseRawFileChecker)):
default_scope = WarningScope.LINE
# TODO: 3.0: Remove deprecated if-statement
elif implements(self, (IRawChecker, ITokenChecker)):
warnings.warn( # pragma: no cover
"Checkers should subclass BaseTokenChecker or BaseRawFileChecker "
"instead of using the __implements__ mechanism. Use of __implements__ "
"will no longer be supported in pylint 3.0",
DeprecationWarning,
)
default_scope = WarningScope.LINE # pragma: no cover
else:
default_scope = WarningScope.NODE
if isinstance(self, (BaseTokenChecker, BaseRawFileChecker)):
Pierre-Sassoulas marked this conversation as resolved.
Show resolved Hide resolved
default_scope = WarningScope.LINE
else:
default_scope = WarningScope.NODE
options: ExtraMessageOptions = {}
if len(msg_tuple) == 4:
(msg, symbol, descr, options) = msg_tuple # type: ignore[misc]
Expand Down
44 changes: 2 additions & 42 deletions pylint/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@

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

Expand Down Expand Up @@ -53,45 +51,7 @@ class Confidence(NamedTuple):
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):
class IChecker:
"""Base interface, to be used only for sub interfaces definition."""

def open(self) -> None:
Expand Down Expand Up @@ -127,7 +87,7 @@ class IAstroidChecker(IChecker):
"""


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

def handle_message(self, msg: Message) -> None:
Expand Down
32 changes: 0 additions & 32 deletions pylint/lint/pylinter.py
Original file line number Diff line number Diff line change
Expand Up @@ -976,41 +976,9 @@ def _astroid_module_checker(
tokencheckers = [
c for c in _checkers if isinstance(c, checkers.BaseTokenChecker)
]
# TODO: 3.0: Remove deprecated for-loop
for c in _checkers:
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
if (
interfaces.implements(c, interfaces.ITokenChecker)
and c not in tokencheckers
and c is not self
):
tokencheckers.append(c) # type: ignore[arg-type] # pragma: no cover
warnings.warn( # pragma: no cover
"Checkers should subclass BaseTokenChecker "
"instead of using the __implements__ mechanism. Use of __implements__ "
"will no longer be supported in pylint 3.0",
DeprecationWarning,
)
rawcheckers = [
c for c in _checkers if isinstance(c, checkers.BaseRawFileChecker)
]
# TODO: 3.0: Remove deprecated if-statement
for c in _checkers:
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
if (
interfaces.implements(c, interfaces.IRawChecker)
and c not in rawcheckers
):
rawcheckers.append(c) # type: ignore[arg-type] # pragma: no cover
warnings.warn( # pragma: no cover
"Checkers should subclass BaseRawFileChecker "
"instead of using the __implements__ mechanism. Use of __implements__ "
"will no longer be supported in pylint 3.0",
DeprecationWarning,
)
# notify global begin
for checker in _checkers:
checker.open()
walker.add_checker(checker)
Expand Down
7 changes: 0 additions & 7 deletions pylint/pyreverse/diagrams.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,13 +207,6 @@ def extract_relationships(self) -> None:
self.add_relationship(obj, par_obj, "specialization")
except KeyError:
continue
# implements link
for impl_node in node.implements:
try:
impl_obj = self.object_from_node(impl_node)
self.add_relationship(obj, impl_obj, "implements")
except KeyError:
continue

# associations & aggregations links
for name, values in list(node.aggregations_type.items()):
Expand Down
45 changes: 2 additions & 43 deletions pylint/pyreverse/inspector.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,11 @@
import collections
import os
import traceback
import warnings
from abc import ABC, abstractmethod
from collections.abc import Generator
from typing import Any, Callable, Optional
from typing import Callable, Optional

import astroid
from astroid import nodes, util
from astroid import nodes

from pylint import constants
from pylint.pyreverse import utils
Expand All @@ -39,27 +37,6 @@ def _astroid_wrapper(
return None


def interfaces(node: nodes.ClassDef) -> Generator[Any, None, None]:
"""Return an iterator on interfaces implemented by the given class node."""
try:
implements = astroid.bases.Instance(node).getattr("__implements__")[0]
except astroid.exceptions.NotFoundError:
return
if implements.frame(future=True) is not node:
return
found = set()
missing = False
for iface in nodes.unpack_infer(implements):
if isinstance(iface, util.UninferableBase):
missing = True
continue
if iface not in found:
found.add(iface)
yield iface
if missing:
raise astroid.exceptions.InferenceError()


class IdGeneratorMixIn:
"""Mixin adding the ability to generate integer uid."""

Expand Down Expand Up @@ -194,24 +171,6 @@ def visit_classdef(self, node: nodes.ClassDef) -> None:
if not isinstance(assignattr, nodes.Unknown):
self.associations_handler.handle(assignattr, node)
self.handle_assignattr_type(assignattr, node)
# resolve implemented interface
try:
ifaces = interfaces(node)
if ifaces is not None:
node.implements = list(ifaces)
if node.implements:
# TODO: 3.0: Remove support for __implements__
warnings.warn(
"pyreverse will drop support for resolving and displaying "
"implemented interfaces in pylint 3.0. The implementation "
"relies on the '__implements__' attribute proposed in PEP 245"
", which was rejected in 2006.",
DeprecationWarning,
)
else:
node.implements = []
except astroid.InferenceError:
node.implements = []

def visit_functiondef(self, node: nodes.FunctionDef) -> None:
"""Visit an astroid.Function node.
Expand Down
8 changes: 0 additions & 8 deletions pylint/reporters/base_reporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

import os
import sys
import warnings
from typing import TYPE_CHECKING, TextIO
from warnings import warn

Expand All @@ -31,13 +30,6 @@ class BaseReporter:
"""Name of the reporter."""

def __init__(self, output: TextIO | None = None) -> None:
if getattr(self, "__implements__", None):
warnings.warn(
"Using the __implements__ inheritance pattern for BaseReporter is no "
"longer supported. Child classes should only inherit BaseReporter",
DeprecationWarning,
stacklevel=2,
)
self.linter: PyLinter
self.section = 0
self.out: TextIO = output or sys.stdout
Expand Down
1 change: 0 additions & 1 deletion tests/data/clientmodule_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

class Ancestor:
""" Ancestor method """
__implements__ = (Interface,)
cls_member = DoNothing()

def __init__(self, value):
Expand Down
1 change: 0 additions & 1 deletion tests/pyreverse/data/classes_No_Name.dot
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ charset="utf-8"
"data.property_pattern.PropertyPatterns" [color="black", fontcolor="black", label=<{PropertyPatterns|prop1<br ALIGN="LEFT"/>prop2<br ALIGN="LEFT"/>|}>, shape="record", style="solid"];
"data.clientmodule_test.Specialization" [color="black", fontcolor="black", label=<{Specialization|TYPE : str<br ALIGN="LEFT"/>relation<br ALIGN="LEFT"/>relation2<br ALIGN="LEFT"/>top : str<br ALIGN="LEFT"/>|from_value(value: int)<br ALIGN="LEFT"/>increment_value(): None<br ALIGN="LEFT"/>transform_value(value: int): int<br ALIGN="LEFT"/>}>, shape="record", style="solid"];
"data.clientmodule_test.Specialization" -> "data.clientmodule_test.Ancestor" [arrowhead="empty", arrowtail="none"];
"data.clientmodule_test.Ancestor" -> "data.suppliermodule_test.Interface" [arrowhead="empty", arrowtail="node", style="dashed"];
"data.suppliermodule_test.DoNothing" -> "data.clientmodule_test.Ancestor" [arrowhead="diamond", arrowtail="none", fontcolor="green", label="cls_member", style="solid"];
"data.suppliermodule_test.DoNothing" -> "data.clientmodule_test.Specialization" [arrowhead="diamond", arrowtail="none", fontcolor="green", label="relation", style="solid"];
"data.suppliermodule_test.DoNothing2" -> "data.clientmodule_test.Specialization" [arrowhead="odiamond", arrowtail="none", fontcolor="green", label="relation2", style="solid"];
Expand Down
1 change: 0 additions & 1 deletion tests/pyreverse/data/classes_No_Name.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
transform_value(value: int) int
}
Specialization --|> Ancestor
Ancestor ..|> Interface
DoNothing --* Ancestor : cls_member
DoNothing --* Specialization : relation
DoNothing2 --o Specialization : relation2
Expand Down
1 change: 0 additions & 1 deletion tests/pyreverse/data/classes_No_Name.mmd
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ classDiagram
transform_value(value: int) int
}
Specialization --|> Ancestor
Ancestor ..|> Interface
DoNothing --* Ancestor : cls_member
DoNothing --* Specialization : relation
DoNothing2 --o Specialization : relation2
1 change: 0 additions & 1 deletion tests/pyreverse/data/classes_No_Name.puml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ class "Specialization" as data.clientmodule_test.Specialization {
transform_value(value: int) -> int
}
data.clientmodule_test.Specialization --|> data.clientmodule_test.Ancestor
data.clientmodule_test.Ancestor ..|> data.suppliermodule_test.Interface
data.suppliermodule_test.DoNothing --* data.clientmodule_test.Ancestor : cls_member
data.suppliermodule_test.DoNothing --* data.clientmodule_test.Specialization : relation
data.suppliermodule_test.DoNothing2 --o data.clientmodule_test.Specialization : relation2
Expand Down
5 changes: 0 additions & 5 deletions tests/pyreverse/data/classes_No_Name.vcg
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,6 @@ graph:{
edge: {sourcename:"data.clientmodule_test.Specialization" targetname:"data.clientmodule_test.Ancestor" arrowstyle:solid
backarrowstyle:none
backarrowsize:10
}
edge: {sourcename:"data.clientmodule_test.Ancestor" targetname:"data.suppliermodule_test.Interface" arrowstyle:solid
backarrowstyle:none
linestyle:dotted
backarrowsize:10
}
edge: {sourcename:"data.suppliermodule_test.DoNothing" targetname:"data.clientmodule_test.Ancestor" arrowstyle:solid
backarrowstyle:none
Expand Down
1 change: 0 additions & 1 deletion tests/pyreverse/data/classes_colorized.dot
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ charset="utf-8"
"data.property_pattern.PropertyPatterns" [color="aliceblue", fontcolor="black", label=<{PropertyPatterns|prop1<br ALIGN="LEFT"/>prop2<br ALIGN="LEFT"/>|}>, shape="record", style="filled"];
"data.clientmodule_test.Specialization" [color="aliceblue", fontcolor="black", label=<{Specialization|TYPE : str<br ALIGN="LEFT"/>relation<br ALIGN="LEFT"/>relation2<br ALIGN="LEFT"/>top : str<br ALIGN="LEFT"/>|from_value(value: int)<br ALIGN="LEFT"/>increment_value(): None<br ALIGN="LEFT"/>transform_value(value: int): int<br ALIGN="LEFT"/>}>, shape="record", style="filled"];
"data.clientmodule_test.Specialization" -> "data.clientmodule_test.Ancestor" [arrowhead="empty", arrowtail="none"];
"data.clientmodule_test.Ancestor" -> "data.suppliermodule_test.Interface" [arrowhead="empty", arrowtail="node", style="dashed"];
"data.suppliermodule_test.DoNothing" -> "data.clientmodule_test.Ancestor" [arrowhead="diamond", arrowtail="none", fontcolor="green", label="cls_member", style="solid"];
"data.suppliermodule_test.DoNothing" -> "data.clientmodule_test.Specialization" [arrowhead="diamond", arrowtail="none", fontcolor="green", label="relation", style="solid"];
"data.suppliermodule_test.DoNothing2" -> "data.clientmodule_test.Specialization" [arrowhead="odiamond", arrowtail="none", fontcolor="green", label="relation2", style="solid"];
Expand Down
1 change: 0 additions & 1 deletion tests/pyreverse/data/classes_colorized.puml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ class "Specialization" as data.clientmodule_test.Specialization #aliceblue {
transform_value(value: int) -> int
}
data.clientmodule_test.Specialization --|> data.clientmodule_test.Ancestor
data.clientmodule_test.Ancestor ..|> data.suppliermodule_test.Interface
data.suppliermodule_test.DoNothing --* data.clientmodule_test.Ancestor : cls_member
data.suppliermodule_test.DoNothing --* data.clientmodule_test.Specialization : relation
data.suppliermodule_test.DoNothing2 --o data.clientmodule_test.Specialization : relation2
Expand Down
4 changes: 1 addition & 3 deletions tests/pyreverse/test_diadefs.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,12 @@ class TestDefaultDiadefGenerator:
("aggregation", "DoNothing2", "Specialization"),
("association", "DoNothing", "Ancestor"),
("association", "DoNothing", "Specialization"),
("implements", "Ancestor", "Interface"),
("specialization", "Specialization", "Ancestor"),
]

def test_extract_relations(self, HANDLER: DiadefsHandler, PROJECT: Project) -> None:
"""Test extract_relations between classes."""
with pytest.warns(DeprecationWarning):
cd = DefaultDiadefGenerator(Linker(PROJECT), HANDLER).visit(PROJECT)[1]
cd = DefaultDiadefGenerator(Linker(PROJECT), HANDLER).visit(PROJECT)[1]
cd.extract_relationships()
relations = _process_relations(cd.relationships)
assert relations == self._should_rels
Expand Down
Loading