diff --git a/pylint/config/argument.py b/pylint/config/argument.py index 3bf9908241..30a5fd1753 100644 --- a/pylint/config/argument.py +++ b/pylint/config/argument.py @@ -19,9 +19,8 @@ from pylint import interfaces from pylint import utils as pylint_utils -from pylint.config.callback_actions import _CallbackAction, _ExtendAction +from pylint.config.callback_actions import _CallbackAction from pylint.config.deprecation_actions import _NewNamesAction, _OldNamesAction -from pylint.constants import PY38_PLUS _ArgumentTypes = Union[ str, @@ -371,11 +370,7 @@ def __init__( choices: list[str] | None, dest: str | None, ) -> None: - # The extend action is included in the stdlib from 3.8+ - if PY38_PLUS: - action_class = argparse._ExtendAction - else: - action_class = _ExtendAction # type: ignore[assignment] + action_class = argparse._ExtendAction self.dest = dest """The destination of the argument.""" diff --git a/pylint/config/callback_actions.py b/pylint/config/callback_actions.py index 7c93f25537..0044e1fcd2 100644 --- a/pylint/config/callback_actions.py +++ b/pylint/config/callback_actions.py @@ -54,27 +54,6 @@ def __call__( return None -class _ExtendAction(argparse._AppendAction): - """Action that adds the value to a pre-existing list. - - It is directly copied from the stdlib implementation which is only available - on 3.8+. - """ - - def __call__( - self, - parser: argparse.ArgumentParser, - namespace: argparse.Namespace, - values: str | Sequence[Any] | None, - option_string: str | None = None, - ) -> None: - assert isinstance(values, (tuple, list)) - current = getattr(namespace, self.dest, []) - assert isinstance(current, list) - current.extend(values) - setattr(namespace, self.dest, current) - - class _AccessRunObjectAction(_CallbackAction): """Action that has access to the Run object.""" diff --git a/pylint/testutils/checker_test_case.py b/pylint/testutils/checker_test_case.py index 343eb82540..3ffbbc44ad 100644 --- a/pylint/testutils/checker_test_case.py +++ b/pylint/testutils/checker_test_case.py @@ -10,7 +10,7 @@ from astroid import nodes -from pylint.constants import IS_PYPY, PY38_PLUS, PY39_PLUS +from pylint.constants import IS_PYPY, PY39_PLUS from pylint.testutils.global_test_linter import linter from pylint.testutils.output_line import MessageTest from pylint.testutils.unittest_linter import UnittestLinter @@ -76,7 +76,7 @@ def assertAddsMessages( assert expected_msg.line == gotten_msg.line, msg assert expected_msg.col_offset == gotten_msg.col_offset, msg - if PY38_PLUS and not IS_PYPY or PY39_PLUS: + if not IS_PYPY or PY39_PLUS: assert expected_msg.end_line == gotten_msg.end_line, msg assert expected_msg.end_col_offset == gotten_msg.end_col_offset, msg diff --git a/pylint/testutils/configuration_test.py b/pylint/testutils/configuration_test.py index 5ddb2c03bb..a38c8646bb 100644 --- a/pylint/testutils/configuration_test.py +++ b/pylint/testutils/configuration_test.py @@ -9,13 +9,11 @@ import copy import json import logging -import re import unittest from pathlib import Path from typing import Any, Dict from unittest.mock import Mock -from pylint.constants import PY38_PLUS from pylint.lint import Run # We use Any in this typing because the configuration contains real objects and constants @@ -24,13 +22,6 @@ PylintConfiguration = Dict[str, ConfigurationValue] -if not PY38_PLUS: - # We need to deepcopy a compiled regex pattern - # In python 3.6 and 3.7 this requires a hack - # See https://stackoverflow.com/a/56935186 - copy._deepcopy_dispatch[type(re.compile(""))] = lambda r, _: r # type: ignore[attr-defined] - - def get_expected_or_default( tested_configuration_file: str | Path, suffix: str, diff --git a/pylint/testutils/functional/lint_module_output_update.py b/pylint/testutils/functional/lint_module_output_update.py index 8855fd1aab..072e9f7244 100644 --- a/pylint/testutils/functional/lint_module_output_update.py +++ b/pylint/testutils/functional/lint_module_output_update.py @@ -7,10 +7,6 @@ import csv import os -from _pytest.config import Config - -from pylint.constants import PY38_PLUS -from pylint.testutils.functional.test_file import FunctionalTestFile from pylint.testutils.lint_module_test import LintModuleTest, MessageCounter from pylint.testutils.output_line import OutputLine @@ -28,17 +24,6 @@ class TestDialect(csv.excel): csv.register_dialect("test", TestDialect) - def __init__( - self, test_file: FunctionalTestFile, config: Config | None = None - ) -> None: - if not PY38_PLUS: - raise RuntimeError( - "You need at least python 3.8 for the functional test updater to work. " - "This is because python 3.8 includes a new AST parser, which amongst others " - "returns the end line and end column of most nodes." - ) - super().__init__(test_file, config) - def _check_output_text( self, _: MessageCounter, diff --git a/pylint/testutils/output_line.py b/pylint/testutils/output_line.py index 95f24cc129..c979a049c3 100644 --- a/pylint/testutils/output_line.py +++ b/pylint/testutils/output_line.py @@ -9,7 +9,6 @@ from astroid import nodes -from pylint.constants import PY38_PLUS from pylint.interfaces import UNDEFINED, Confidence from pylint.message.message import Message @@ -60,13 +59,7 @@ def from_msg(cls, msg: Message, check_endline: bool = True) -> OutputLine: @staticmethod def _get_column(column: str | int) -> int: - """Handle column numbers except for python < 3.8. - - The ast parser in those versions doesn't return them. - """ - if not PY38_PLUS: - # We check the column only for the new better ast parser introduced in python 3.8 - return 0 # pragma: no cover + """Handle column numbers.""" return int(column) @staticmethod diff --git a/tests/testutils/test_lint_module_output_update.py b/tests/testutils/test_lint_module_output_update.py index a8bfc5fde7..038dc77ed3 100644 --- a/tests/testutils/test_lint_module_output_update.py +++ b/tests/testutils/test_lint_module_output_update.py @@ -12,7 +12,7 @@ import pytest -from pylint.constants import IS_PYPY, PY38_PLUS, PY39_PLUS +from pylint.constants import IS_PYPY, PY39_PLUS from pylint.testutils import FunctionalTestFile, LintModuleTest from pylint.testutils.functional import LintModuleOutputUpdate @@ -35,15 +35,6 @@ def inner(base: str) -> tuple[Path, Path, LintModuleOutputUpdate]: return inner -@pytest.mark.skipif(PY38_PLUS, reason="Requires python 3.7 or lower") -def test_not_py38(tmp_path: Path) -> None: - with pytest.raises(RuntimeError, match="new AST parser"): - LintModuleOutputUpdate( - test_file=FunctionalTestFile(str(tmp_path), str(tmp_path / "filename.py")) - ) - - -@pytest.mark.skipif(not PY38_PLUS, reason="Requires python 3.8 or superior") def test_lint_module_output_update_fail_before( lint_module_fixture: Callable[[str], tuple[Path, Path, LintModuleOutputUpdate]] ) -> None: @@ -56,7 +47,6 @@ def test_lint_module_output_update_fail_before( assert not expected_output_file.exists() -@pytest.mark.skipif(not PY38_PLUS, reason="Requires python 3.8 or superior") def test_lint_module_output_update_effective( lint_module_fixture: Callable[[str], tuple[Path, Path, LintModuleOutputUpdate]] ) -> None: @@ -71,7 +61,6 @@ def test_lint_module_output_update_effective( ) -@pytest.mark.skipif(not PY38_PLUS, reason="Requires python 3.8 or superior") def test_lint_module_output_update_remove_useless_txt( lint_module_fixture: Callable[[str], tuple[Path, Path, LintModuleOutputUpdate]] ) -> None: @@ -84,7 +73,7 @@ def test_lint_module_output_update_remove_useless_txt( @pytest.mark.skipif( - not PY38_PLUS or (IS_PYPY and not PY39_PLUS), + IS_PYPY and not PY39_PLUS, reason="Requires accurate 'end_col' value to update output", ) @pytest.mark.parametrize( diff --git a/tests/testutils/test_output_line.py b/tests/testutils/test_output_line.py index 8e9cf2800b..311ae9340a 100644 --- a/tests/testutils/test_output_line.py +++ b/tests/testutils/test_output_line.py @@ -10,7 +10,6 @@ import pytest -from pylint.constants import PY38_PLUS from pylint.interfaces import HIGH, INFERENCE, Confidence from pylint.message import Message from pylint.testutils.output_line import OutputLine @@ -62,12 +61,10 @@ def test_output_line() -> None: def test_output_line_from_message(message: _MessageCallable) -> None: """Test that the OutputLine NamedTuple is instantiated correctly with from_msg.""" - expected_column = 2 if PY38_PLUS else 0 - output_line = OutputLine.from_msg(message()) assert output_line.symbol == "missing-docstring" assert output_line.lineno == 1 - assert output_line.column == expected_column + assert output_line.column == 2 assert output_line.end_lineno == 1 assert output_line.end_column == 3 assert output_line.object == "obj" @@ -77,7 +74,7 @@ def test_output_line_from_message(message: _MessageCallable) -> None: output_line_with_end = OutputLine.from_msg(message(), True) assert output_line_with_end.symbol == "missing-docstring" assert output_line_with_end.lineno == 1 - assert output_line_with_end.column == expected_column + assert output_line_with_end.column == 2 assert output_line_with_end.end_lineno == 1 assert output_line_with_end.end_column == 3 assert output_line_with_end.object == "obj" @@ -87,7 +84,7 @@ def test_output_line_from_message(message: _MessageCallable) -> None: output_line_without_end = OutputLine.from_msg(message(), False) assert output_line_without_end.symbol == "missing-docstring" assert output_line_without_end.lineno == 1 - assert output_line_without_end.column == expected_column + assert output_line_without_end.column == 2 assert output_line_without_end.end_lineno is None assert output_line_without_end.end_column is None assert output_line_without_end.object == "obj" @@ -102,11 +99,10 @@ def test_output_line_to_csv(confidence: Confidence, message: _MessageCallable) - """ output_line = OutputLine.from_msg(message(confidence), True) csv = output_line.to_csv() - expected_column = "2" if PY38_PLUS else "0" assert csv == ( "missing-docstring", "1", - expected_column, + "2", "1", "3", "obj", @@ -116,11 +112,10 @@ def test_output_line_to_csv(confidence: Confidence, message: _MessageCallable) - output_line_without_end = OutputLine.from_msg(message(confidence), False) csv = output_line_without_end.to_csv() - expected_column = "2" if PY38_PLUS else "0" assert csv == ( "missing-docstring", "1", - expected_column, + "2", "None", "None", "obj", @@ -134,13 +129,12 @@ def test_output_line_from_csv() -> None: Test OutputLine of length 8. """ proper_csv = ["missing-docstring", "1", "2", "1", "None", "obj", "msg", "HIGH"] - expected_column = 2 if PY38_PLUS else 0 output_line = OutputLine.from_csv(proper_csv) assert output_line == OutputLine( symbol="missing-docstring", lineno=1, - column=expected_column, + column=2, end_lineno=1, end_column=None, object="obj", @@ -151,7 +145,7 @@ def test_output_line_from_csv() -> None: assert output_line_with_end == OutputLine( symbol="missing-docstring", lineno=1, - column=expected_column, + column=2, end_lineno=1, end_column=None, object="obj", @@ -162,7 +156,7 @@ def test_output_line_from_csv() -> None: assert output_line_without_end == OutputLine( symbol="missing-docstring", lineno=1, - column=expected_column, + column=2, end_lineno=None, end_column=None, object="obj",