diff options
author | Pierre Sassoulas <pierre.sassoulas@gmail.com> | 2022-03-08 11:01:40 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-08 11:01:40 +0100 |
commit | 444e9e1a6e67dba23d050e638ae027ee44414a08 (patch) | |
tree | fb4eb437a85546e9839927f5d5db3968387d60ca | |
parent | 4649153dae5d55b3ac01787a7a61b25624077526 (diff) | |
download | pylint-git-444e9e1a6e67dba23d050e638ae027ee44414a08.tar.gz |
Restore the useful part of the python3 checker (#5843)
* Reinstate checks from the python3 checker that are still useful for py3
Closes #5025
Co-authored-by: Daniƫl van Noord <13665637+DanielNoord@users.noreply.github.com>
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | doc/whatsnew/2.13.rst | 6 | ||||
-rw-r--r-- | pylint/constants.py | 5 | ||||
-rw-r--r-- | pylint/extensions/__init__.py | 2 | ||||
-rw-r--r-- | pylint/extensions/code_style.py | 2 | ||||
-rw-r--r-- | pylint/extensions/eq_without_hash.py | 39 | ||||
-rw-r--r-- | tests/functional/ext/eq_without_hash/eq_without_hash.py | 11 | ||||
-rw-r--r-- | tests/functional/ext/eq_without_hash/eq_without_hash.rc | 2 | ||||
-rw-r--r-- | tests/functional/ext/eq_without_hash/eq_without_hash.txt | 1 |
9 files changed, 68 insertions, 6 deletions
@@ -53,6 +53,12 @@ Release date: TBA Closes #5486 +* Reinstated checks from the python3 checker that are still useful for python 3 + (``eq-without-hash``). This is now in the ``pylint.extensions.eq_without_hash`` optional + extension. + + Closes #5025 + * Added several checkers to deal with unicode security issues (see `Trojan Sources <https://trojansource.codes/>`_ and `PEP 672 <https://www.python.org/dev/peps/pep-0672/>`_ for details) that also diff --git a/doc/whatsnew/2.13.rst b/doc/whatsnew/2.13.rst index e7fc63b88..6fe17d995 100644 --- a/doc/whatsnew/2.13.rst +++ b/doc/whatsnew/2.13.rst @@ -110,6 +110,12 @@ Other Changes Closes #352 +* Reinstated checks from the python3 checker that are still useful for python 3 + (``eq-without-hash``). This is now in the ``pylint.extensions.eq_without_hash`` optional + extension. + + Closes #5025 + * Fix false-negative for ``assignment-from-none`` checker with list.sort() method. Closes #5722 diff --git a/pylint/constants.py b/pylint/constants.py index c3b94863d..1a06ea832 100644 --- a/pylint/constants.py +++ b/pylint/constants.py @@ -80,9 +80,7 @@ class DeletedMessage(NamedTuple): old_names: List[Tuple[str, str]] = [] -DELETED_MSGID_PREFIXES = [ - 16, # the PY3K+ checker, see https://github.com/PyCQA/pylint/pull/4942 -] +DELETED_MSGID_PREFIXES: List[int] = [] DELETED_MESSAGES = [ # Everything until the next comment is from the @@ -139,7 +137,6 @@ DELETED_MESSAGES = [ DeletedMessage("W1638", "range-builtin-not-iterating"), DeletedMessage("W1639", "filter-builtin-not-iterating"), DeletedMessage("W1640", "using-cmp-argument"), - DeletedMessage("W1641", "eq-without-hash"), DeletedMessage("W1642", "div-method"), DeletedMessage("W1643", "idiv-method"), DeletedMessage("W1644", "rdiv-method"), diff --git a/pylint/extensions/__init__.py b/pylint/extensions/__init__.py index c34836101..4af3aefb1 100644 --- a/pylint/extensions/__init__.py +++ b/pylint/extensions/__init__.py @@ -10,7 +10,7 @@ if TYPE_CHECKING: def initialize(linter: "PyLinter") -> None: - """Initialize linter with checkers in the extensions directory.""" + """Initialize linter with checkers in the extensions' directory.""" register_plugins(linter, __path__[0]) diff --git a/pylint/extensions/code_style.py b/pylint/extensions/code_style.py index 7082c991c..5a3e3ba17 100644 --- a/pylint/extensions/code_style.py +++ b/pylint/extensions/code_style.py @@ -28,7 +28,7 @@ class CodeStyleChecker(BaseChecker): i.e. detect a common issue or improve performance => it should probably be part of the core checker classes 2. Is it something that would improve code consistency, - maybe because it's slightly better with regards to performance + maybe because it's slightly better with regard to performance and therefore preferred => this is the right place 3. Everything else should go into another extension """ diff --git a/pylint/extensions/eq_without_hash.py b/pylint/extensions/eq_without_hash.py new file mode 100644 index 000000000..b0dd6ce46 --- /dev/null +++ b/pylint/extensions/eq_without_hash.py @@ -0,0 +1,39 @@ +# 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 + +"""This is the remnant of the python3 checker. It was removed because +the transition from python 2 to python3 is behind us, but some checks +are still useful in python3 after all. +See https://github.com/PyCQA/pylint/issues/5025 +""" + +from astroid import nodes + +from pylint import checkers, interfaces +from pylint.checkers import utils +from pylint.lint import PyLinter + + +class EqWithoutHash(checkers.BaseChecker): + + __implements__ = interfaces.IAstroidChecker + name = "eq-without-hash" + + msgs = { + "W1641": ( + "Implementing __eq__ without also implementing __hash__", + "eq-without-hash", + "Used when a class implements __eq__ but not __hash__. Objects get " + "None as their default __hash__ implementation if they also implement __eq__.", + ), + } + + @utils.check_messages("eq-without-hash") + def visit_classdef(self, node: nodes.ClassDef) -> None: + locals_and_methods = set(node.locals).union(x.name for x in node.mymethods()) + if "__eq__" in locals_and_methods and "__hash__" not in locals_and_methods: + self.add_message("eq-without-hash", node=node, confidence=interfaces.HIGH) + + +def register(linter: PyLinter) -> None: + linter.register_checker(EqWithoutHash(linter)) diff --git a/tests/functional/ext/eq_without_hash/eq_without_hash.py b/tests/functional/ext/eq_without_hash/eq_without_hash.py new file mode 100644 index 000000000..a28afc97b --- /dev/null +++ b/tests/functional/ext/eq_without_hash/eq_without_hash.py @@ -0,0 +1,11 @@ +"""Regression test for #5025""" + +# pylint: disable=invalid-name, missing-docstring, too-few-public-methods + + +class AClass: # [eq-without-hash] + def __init__(self) -> None: + self.x = 5 + + def __eq__(self, other: object) -> bool: + return isinstance(other, AClass) and other.x == self.x diff --git a/tests/functional/ext/eq_without_hash/eq_without_hash.rc b/tests/functional/ext/eq_without_hash/eq_without_hash.rc new file mode 100644 index 000000000..5a4c9fcce --- /dev/null +++ b/tests/functional/ext/eq_without_hash/eq_without_hash.rc @@ -0,0 +1,2 @@ +[MASTER] +load-plugins=pylint.extensions.eq_without_hash, diff --git a/tests/functional/ext/eq_without_hash/eq_without_hash.txt b/tests/functional/ext/eq_without_hash/eq_without_hash.txt new file mode 100644 index 000000000..b7e2dc46d --- /dev/null +++ b/tests/functional/ext/eq_without_hash/eq_without_hash.txt @@ -0,0 +1 @@ +eq-without-hash:6:0:11:62:AClass:Implementing __eq__ without also implementing __hash__:HIGH |