Skip to content

Commit

Permalink
Add checkers for typing.final for Python version 3.8 or later
Browse files Browse the repository at this point in the history
- Move checker logic to its own method
- tuple -> list to be consistent with the existing module style
- Doc formatting tweak

    Closes pylint-dev#3197
  • Loading branch information
mbyrnepr2 committed Oct 9, 2021
1 parent 68d0998 commit 43741b8
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 6 deletions.
Binary file added doc/.DS_Store
Binary file not shown.
2 changes: 2 additions & 0 deletions doc/whatsnew/2.12.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ New checkers
============

* Checkers for ``typing.final``

* Added ``overridden-final-method``: Emitted when a method which is annotated with ``typing.final`` is overridden

* Added ``subclassed-final-class``: Emitted when a class which is annotated with ``typing.final`` is subclassed

Closes #3197
Expand Down
23 changes: 17 additions & 6 deletions pylint/checkers/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,7 @@ def visit_classdef(self, node: nodes.ClassDef) -> None:
self.add_message("no-init", args=node, node=node)
self._check_slots(node)
self._check_proper_bases(node)
self._check_typing_final(node)
self._check_consistent_mro(node)

def _check_consistent_mro(self, node):
Expand All @@ -885,11 +886,10 @@ def _check_consistent_mro(self, node):
# Old style class, there's no mro so don't do anything.
pass

def _check_proper_bases(self, node: nodes.ClassDef) -> None:
def _check_proper_bases(self, node):
"""
Detect that a class:
- inherits something which is not a class or a type
- does not subclass a class decorated with typing.final
Detect that a class inherits something which is not
a class or a type
"""
for base in node.bases:
ancestor = safe_infer(base)
Expand All @@ -909,7 +909,18 @@ def _check_proper_bases(self, node: nodes.ClassDef) -> None:
self.add_message(
"useless-object-inheritance", args=node.name, node=node
)
if decorated_with(ancestor, ("typing.final",)) and PY38_PLUS:

def _check_typing_final(self, node: nodes.ClassDef) -> None:
"""Detect that a class does not subclass a class decorated with `typing.final`"""
for base in node.bases:
ancestor = safe_infer(base)
if not ancestor:
continue
if (
isinstance(ancestor, nodes.ClassDef)
and decorated_with(ancestor, ["typing.final"])
and PY38_PLUS
):
self.add_message(
"subclassed-final-class",
args=(node.name, ancestor.name),
Expand Down Expand Up @@ -1365,7 +1376,7 @@ def _check_invalid_overridden_method(self, function_node, parent_function_node):
args=(function_node.name, "non-async", "async"),
node=function_node,
)
if decorated_with(parent_function_node, ("typing.final",)) and PY38_PLUS:
if decorated_with(parent_function_node, ["typing.final"]) and PY38_PLUS:
self.add_message(
"overridden-final-method",
args=(function_node.name, parent_function_node.parent.name),
Expand Down

0 comments on commit 43741b8

Please sign in to comment.