diff options
author | Andreas Finkler <3929834+DudeNr33@users.noreply.github.com> | 2022-05-27 19:12:05 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-27 19:12:05 +0200 |
commit | 4fb07dfe2c93ed9dd36bae223f75d632a7b498e2 (patch) | |
tree | d674414fe414cfaf3ee271f75390d633c4696bfc | |
parent | 3e2c1a0c9c990cba49ace02f51d4117a45686e39 (diff) | |
download | pylint-git-4fb07dfe2c93ed9dd36bae223f75d632a7b498e2.tar.gz |
Refactor and deprecate resolving of interface implementations in `pyreverse` (#6713)
* Remove variables and code paths that are always static in productive use.
* Add deprecation warning if an interface defined through ``__implements__`` is found.
* Update pylint/pyreverse/inspector.py
Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
* Group changelog entries together with refactor from #6712
Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | doc/whatsnew/2.14.rst | 13 | ||||
-rw-r--r-- | pylint/pyreverse/inspector.py | 41 | ||||
-rw-r--r-- | tests/pyreverse/test_inspector.py | 17 |
4 files changed, 47 insertions, 29 deletions
@@ -181,6 +181,11 @@ Release date: TBA Ref #6712 +* ``pyreverse``: Resolving and displaying implemented interfaces that are defined by the ``__implements__`` + attribute has been deprecated and will be removed in 3.0. + + Ref #6713 + * ``interfaces.implements`` has been deprecated and will be removed in 3.0. Please use standard inheritance patterns instead of ``__implements__``. diff --git a/doc/whatsnew/2.14.rst b/doc/whatsnew/2.14.rst index 3e4fd87e6..d5caee73a 100644 --- a/doc/whatsnew/2.14.rst +++ b/doc/whatsnew/2.14.rst @@ -281,10 +281,6 @@ Other Changes Closes #6644 -* ``pylint.pyreverse.ASTWalker`` has been removed, as it was only used internally by a single child class. - - Ref #6712 - Deprecations ============ @@ -387,6 +383,15 @@ Deprecations Ref #5392 +* ``pylint.pyreverse.ASTWalker`` has been removed, as it was only used internally by a single child class. + + Ref #6712 + +* ``pyreverse``: Resolving and displaying implemented interfaces that are defined by the ``__implements__`` + attribute has been deprecated and will be removed in 3.0. + + Ref #6713 + * ``is_class_subscriptable_pep585_with_postponed_evaluation_enabled`` has been deprecated. Use ``is_postponed_evaluation_enabled(node) and is_node_in_type_annotation_context(node)`` instead. diff --git a/pylint/pyreverse/inspector.py b/pylint/pyreverse/inspector.py index 35e993f11..8f0f9bcfc 100644 --- a/pylint/pyreverse/inspector.py +++ b/pylint/pyreverse/inspector.py @@ -12,6 +12,7 @@ from __future__ import annotations import collections import os import traceback +import warnings from collections.abc import Generator from typing import Any, Callable, Optional @@ -24,11 +25,6 @@ from pylint.pyreverse import utils _WrapperFuncT = Callable[[Callable[[str], nodes.Module], str], Optional[nodes.Module]] -def _iface_hdlr(_: nodes.NodeNG | Any) -> bool: - """Handler used by interfaces to handle suspicious interface nodes.""" - return True - - def _astroid_wrapper( func: Callable[[str], nodes.Module], modname: str ) -> nodes.Module | None: @@ -42,17 +38,13 @@ def _astroid_wrapper( return None -def interfaces( - node: nodes.ClassDef, - herited: bool = True, - handler_func: Callable[[nodes.NodeNG | Any], bool] = _iface_hdlr, -) -> Generator[Any, None, 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 not herited and implements.frame(future=True) is not node: + if implements.frame(future=True) is not node: return found = set() missing = False @@ -60,7 +52,7 @@ def interfaces( if iface is astroid.Uninferable: missing = True continue - if iface not in found and handler_func(iface): + if iface not in found: found.add(iface) yield iface if missing: @@ -135,13 +127,9 @@ class Linker(IdGeneratorMixIn, utils.LocalsVisitor): list of implemented interface _objects_ (only on astroid.Class nodes) """ - def __init__( - self, project: Project, inherited_interfaces: bool = False, tag: bool = False - ) -> None: + def __init__(self, project: Project, tag: bool = False) -> None: IdGeneratorMixIn.__init__(self) utils.LocalsVisitor.__init__(self) - # take inherited interface in consideration or not - self.inherited_interfaces = inherited_interfaces # tag nodes or not self.tag = tag # visited project @@ -196,8 +184,18 @@ class Linker(IdGeneratorMixIn, utils.LocalsVisitor): self.handle_assignattr_type(assignattr, node) # resolve implemented interface try: - ifaces = interfaces(node, self.inherited_interfaces) - node.implements = list(ifaces) if ifaces is not None else [] + ifaces = interfaces(node) + if ifaces is not None: + node.implements = list(ifaces) + # 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 = [] @@ -213,11 +211,6 @@ class Linker(IdGeneratorMixIn, utils.LocalsVisitor): if self.tag: node.uid = self.generate_id() - link_project = visit_project - link_module = visit_module - link_class = visit_classdef - link_function = visit_functiondef - def visit_assignname(self, node: nodes.AssignName) -> None: """Visit an astroid.AssignName node. diff --git a/tests/pyreverse/test_inspector.py b/tests/pyreverse/test_inspector.py index db0f4656a..0fd54e8f8 100644 --- a/tests/pyreverse/test_inspector.py +++ b/tests/pyreverse/test_inspector.py @@ -110,7 +110,7 @@ def test_interfaces() -> None: ("Concrete0", ["MyIFace"]), ("Concrete1", ["MyIFace", "AnotherIFace"]), ("Concrete2", ["MyIFace", "AnotherIFace"]), - ("Concrete23", ["MyIFace", "AnotherIFace"]), + ("Concrete23", []), ): klass = module[klass] assert [i.name for i in inspector.interfaces(klass)] == interfaces @@ -130,3 +130,18 @@ def test_project_node(project: Project) -> None: "data.suppliermodule_test", ] assert sorted(project.keys()) == expected + + +def test_interface_deprecation(project: Project) -> None: + linker = inspector.Linker(project) + cls = astroid.extract_node( + ''' + class IMachin: pass + + class Concrete: #@ + """docstring""" + __implements__ = (IMachin,) + ''' + ) + with pytest.warns(DeprecationWarning): + linker.visit_classdef(cls) |