Repository: pylint-dev/pylint-pytest (language: python)

Issue:
Support pylint v3
_From the issue upstream_: https://github.com/pylint-dev/pylint/issues/9144


Discussion / hints:
What the status of this issue ? I would like to help if I can 
It is mostly waiting on me to claim back my OSS time and do some basic sanity checks 😅
(_and my insistence to avoid raising major versions for maximum inclusivity_)

I apologize that my (announced?) timeline of "having this finished" would be ~Nov-15th, and I am "breaking that promise".
ok, there is no plan to fix it before v2 ?
According to Pierre's tries, no: https://github.com/pylint-dev/pylint-pytest/pull/23#issuecomment-1828607407

OTOH, the https://github.com/pylint-dev/pylint-pytest/milestone/1 (all v1.1.x versions) is closed ~1.5w ago, and the https://github.com/pylint-dev/pylint-pytest/milestone/2 is next (i.e., all repo modernizations, which includes upgrading Pythons, dropping `setup.*`, and dropping EOL Pythons) - which will involve raising major version

If there is a "suitable bugfix" to be done for v1s, we can streamline it now (but it "feels like" https://github.com/pylint-dev/pylint/issues/8298 is not fixable in v1)

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 65527d9..9e1c619 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,15 @@
 
 ## [Unreleased]
 
+## [1.1.7] - 2023-12-04
+
+This is a small release to support additionally Pylint v3.
+It should be noted, however, that for linting, Pylint must be v3 or newer (due to backwards-incompatible changes).
+
+### Fixed
+
+* Support pylint v3 and drop v1 (https://github.com/pylint-dev/pylint-pytest/pull/27)
+
 ## [1.1.6] - 2023-11-20
 
 This is a small bugfix release.
diff --git a/pyproject.toml b/pyproject.toml
index 059659c..ea9bec6 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -123,13 +123,11 @@ load-plugins= [
     "pylint.extensions.broad_try_clause",
     "pylint.extensions.check_elif",
     "pylint.extensions.code_style",
-    "pylint.extensions.comparetozero",
     "pylint.extensions.comparison_placement",
     "pylint.extensions.confusing_elif",
     # "pylint.extensions.consider_ternary_expression", # Not a pretty refactoring
     "pylint.extensions.docparams",
     "pylint.extensions.docstyle",
-    "pylint.extensions.emptystring",
     "pylint.extensions.eq_without_hash",
     "pylint.extensions.for_any_all",
     "pylint.extensions.mccabe",
@@ -174,4 +172,8 @@ output-format = "colorized"
 ignored-argument-names = "_.*"
 
 [tool.pylint."messages control"]
-enable = ["useless-suppression"]
+enable = [
+    "useless-suppression",
+    "use-implicit-booleaness-not-comparison-to-zero",
+    "use-implicit-booleaness-not-comparison-to-string",
+]
diff --git a/setup.py b/setup.py
index 9641df3..84500ac 100755
--- a/setup.py
+++ b/setup.py
@@ -28,7 +28,7 @@
     long_description_content_type="text/markdown",
     packages=find_packages(exclude=["tests*", "sandbox"]),
     install_requires=[
-        "pylint<3",
+        "pylint>=2",
         "pytest>=4.6",
     ],
     python_requires=">=3.6",
diff --git a/tox.ini b/tox.ini
index 09dd02e..adf4208 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,11 @@
 [tox]
-envlist = py36,py37,py38,py39,py310,py311
+envlist =
+    py36-pylint2
+    py37-pylint2
+    py38-pylint{2,3}
+    py39-pylint{2,3}
+    py310-pylint{2,3}
+    py311-pylint{2,3}
 skipsdist = True
 passenv =
     FORCE_COLOR
@@ -8,6 +14,8 @@ passenv =
 deps =
     pytest
     pytest-cov
+    pylint2: pylint>2,<3
+    pylint3: pylint>3,<4
 commands =
     pip install --upgrade --editable .
     pytest --cov --cov-append {env:PYTEST_CI_ARGS:} {tty:--color=yes} {posargs:tests}


Test patch:
diff --git a/pylint_pytest/checkers/__init__.py b/pylint_pytest/checkers/__init__.py
index d74c770..f72017f 100644
--- a/pylint_pytest/checkers/__init__.py
+++ b/pylint_pytest/checkers/__init__.py
@@ -1,5 +1,16 @@
 from pylint.checkers import BaseChecker
 
+from pylint_pytest.utils import PYLINT_VERSION_MAJOR
+
 
 class BasePytestChecker(BaseChecker):
+    if PYLINT_VERSION_MAJOR < 3:
+        # todo(maybe-remove): if we only support pylint>=3
+        # Since https://github.com/pylint-dev/pylint/pull/8404, pylint does not need this
+        # __implements__ pattern. keeping it for retro compatibility with pylint==2.x
+        # pylint: disable=import-outside-toplevel,no-name-in-module
+        from pylint.interfaces import IAstroidChecker
+
+        __implements__ = IAstroidChecker
+
     name = "pylint-pytest"
diff --git a/pylint_pytest/checkers/class_attr_loader.py b/pylint_pytest/checkers/class_attr_loader.py
index 6c9b4e9..40d16cf 100644
--- a/pylint_pytest/checkers/class_attr_loader.py
+++ b/pylint_pytest/checkers/class_attr_loader.py
@@ -1,14 +1,12 @@
 from typing import Optional, Set
 
 from astroid import Assign, Attribute, ClassDef, Name
-from pylint.interfaces import IAstroidChecker
 
 from ..utils import _can_use_fixture, _is_class_autouse_fixture
 from . import BasePytestChecker
 
 
 class ClassAttrLoader(BasePytestChecker):
-    __implements__ = IAstroidChecker
     msgs = {"E6400": ("", "pytest-class-attr-loader", "")}
 
     in_setup = False
diff --git a/pylint_pytest/checkers/fixture.py b/pylint_pytest/checkers/fixture.py
index 258e86d..86dd5bb 100644
--- a/pylint_pytest/checkers/fixture.py
+++ b/pylint_pytest/checkers/fixture.py
@@ -5,10 +5,8 @@
 from typing import Set, Tuple
 
 import astroid
-import pylint
 import pytest
 from pylint.checkers.variables import VariablesChecker
-from pylint.interfaces import IAstroidChecker
 
 from ..utils import (
     _can_use_fixture,
@@ -42,7 +40,6 @@ def pytest_collectreport(self, report):
 
 
 class FixtureChecker(BasePytestChecker):
-    __implements__ = IAstroidChecker
     msgs = {
         "W6401": (
             "Using a deprecated @pytest.yield_fixture decorator",
@@ -235,7 +232,7 @@ def visit_functiondef(self, node):
             for arg in node.args.args:
                 self._invoked_with_func_args.add(arg.name)
 
-    # pylint: disable=bad-staticmethod-argument,too-many-branches # The function itself is an if-return logic.
+    # pylint: disable=bad-staticmethod-argument # The function itself is an if-return logic.
     @staticmethod
     def patch_add_message(
         self, msgid, line=None, node=None, args=None, confidence=None, col_offset=None
@@ -314,10 +311,4 @@ def patch_add_message(
         ):
             return
 
-        if int(pylint.__version__.split(".")[0]) >= 2:
-            FixtureChecker._original_add_message(
-                self, msgid, line, node, args, confidence, col_offset
-            )
-        else:
-            # python2 + pylint1.9 backward compatibility
-            FixtureChecker._original_add_message(self, msgid, line, node, args, confidence)
+        FixtureChecker._original_add_message(self, msgid, line, node, args, confidence, col_offset)
diff --git a/pylint_pytest/utils.py b/pylint_pytest/utils.py
index c9fa02f..b044569 100644
--- a/pylint_pytest/utils.py
+++ b/pylint_pytest/utils.py
@@ -1,6 +1,9 @@
 import inspect
 
 import astroid
+import pylint
+
+PYLINT_VERSION_MAJOR = int(pylint.__version__.split(".")[0])
 
 
 def _is_pytest_mark_usefixtures(decorator):
diff --git a/tests/base_tester.py b/tests/base_tester.py
index deed382..c57971e 100644
--- a/tests/base_tester.py
+++ b/tests/base_tester.py
@@ -3,18 +3,12 @@
 from abc import ABC
 from pathlib import Path
 from pprint import pprint
-from typing import Any, Dict, List
+from typing import List, Type
 
 import astroid
-from pylint.testutils import MessageTest, UnittestLinter
-
-try:
-    from pylint.utils import ASTWalker
-except ImportError:
-    # for pylint 1.9
-    from pylint.utils import PyLintASTWalker as ASTWalker
-
 from pylint.checkers import BaseChecker
+from pylint.testutils import MessageTest, UnittestLinter
+from pylint.utils import ASTWalker
 
 import pylint_pytest.checkers.fixture
 
@@ -29,10 +23,9 @@ def get_test_root_path() -> Path:
 
 class BasePytestTester(ABC):
     CHECKER_CLASS = BaseChecker
-    IMPACTED_CHECKER_CLASSES: List[BaseChecker] = []
+    IMPACTED_CHECKER_CLASSES: List[Type[BaseChecker]] = []
     MSG_ID: str
     msgs: List[MessageTest] = []
-    CONFIG: Dict[str, Any] = {}
 
     def __init_subclass__(cls, **kwargs):
         super().__init_subclass__(**kwargs)
@@ -78,14 +71,10 @@ def setup_method(self):
         self.checker = self.CHECKER_CLASS(self.linter)
         self.impacted_checkers = []
 
-        for key, value in self.CONFIG.items():
-            setattr(self.checker.config, key, value)
         self.checker.open()
 
         for checker_class in self.IMPACTED_CHECKER_CLASSES:
             checker = checker_class(self.linter)
-            for key, value in self.CONFIG.items():
-                setattr(checker.config, key, value)
             checker.open()
             self.impacted_checkers.append(checker)
 
diff --git a/tests/test_regression.py b/tests/test_regression.py
index e53f999..a4e7113 100644
--- a/tests/test_regression.py
+++ b/tests/test_regression.py
@@ -1,4 +1,3 @@
-import pylint
 import pytest
 from base_tester import BasePytestTester
 from pylint.checkers.variables import VariablesChecker
@@ -18,9 +17,5 @@ def test_import_twice(self, enable_plugin):
         """catch a coding error when using fixture + if + inline import"""
         self.run_linter(enable_plugin)
 
-        if int(pylint.__version__.split(".")[0]) < 2:
-            # for some reason pylint 1.9.5 does not raise unused-import for inline import
-            self.verify_messages(1, msg_id="unused-import")
-        else:
-            self.verify_messages(2, msg_id="unused-import")
+        self.verify_messages(2, msg_id="unused-import")
         self.verify_messages(1, msg_id="redefined-outer-name")