From 28fd5c768dcd3d897609b03cf9b32eca00b1bccf Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Mon, 26 May 2025 08:20:01 -0400 Subject: [PATCH 01/15] Adjust tests that only ran on 3.9 --- .../a/alternative/alternative_union_syntax_error.py | 2 +- .../a/alternative/alternative_union_syntax_error.rc | 3 --- tests/functional/d/deprecated/deprecated_class_py33.py | 5 ----- tests/functional/d/deprecated/deprecated_class_py33.rc | 4 ++-- tests/functional/d/deprecated/deprecated_class_py33.txt | 1 - tests/functional/d/deprecated/deprecated_methods_py39.rc | 4 ++-- tests/functional/d/deprecated/deprecated_module_py39.rc | 4 ++-- .../d/deprecated/deprecated_module_py39_earlier_pyversion.rc | 3 --- tests/functional/i/iterable_context_asyncio.rc | 5 ++++- tests/functional/r/regression/regression_4439.py | 2 +- tests/functional/r/regression/regression_4439.rc | 4 ++-- tests/functional/r/regression/regression_4439.txt | 1 - tests/functional/w/wrong_exception_operation_py37.py | 2 +- tests/functional/w/wrong_exception_operation_py37.rc | 4 ++-- tests/functional/w/wrong_exception_operation_py37.txt | 1 + 15 files changed, 18 insertions(+), 27 deletions(-) delete mode 100644 tests/functional/r/regression/regression_4439.txt diff --git a/tests/functional/a/alternative/alternative_union_syntax_error.py b/tests/functional/a/alternative/alternative_union_syntax_error.py index 5730e2e503..b424e5bde9 100644 --- a/tests/functional/a/alternative/alternative_union_syntax_error.py +++ b/tests/functional/a/alternative/alternative_union_syntax_error.py @@ -23,7 +23,7 @@ lst = [typing.Dict[str, int] | None,] # [unsupported-binary-operation] var1: typing.Dict[str, int | None] # [unsupported-binary-operation] -var2: int | str | None # [unsupported-binary-operation, unsupported-binary-operation] +# var2: int | str | None # false-negative: unsupported-binary-operation, unsupported-binary-operation var3: int | typing.List[str | int] # [unsupported-binary-operation] var4: typing.Dict[typing.Tuple[int, int] | int, None] # [unsupported-binary-operation] diff --git a/tests/functional/a/alternative/alternative_union_syntax_error.rc b/tests/functional/a/alternative/alternative_union_syntax_error.rc index 5dc39b1a65..6f046622fa 100644 --- a/tests/functional/a/alternative/alternative_union_syntax_error.rc +++ b/tests/functional/a/alternative/alternative_union_syntax_error.rc @@ -1,5 +1,2 @@ [main] py-version=3.8 - -[testoptions] -max_pyver=3.10 diff --git a/tests/functional/d/deprecated/deprecated_class_py33.py b/tests/functional/d/deprecated/deprecated_class_py33.py index 470e467baa..13c89a7749 100644 --- a/tests/functional/d/deprecated/deprecated_class_py33.py +++ b/tests/functional/d/deprecated/deprecated_class_py33.py @@ -4,8 +4,3 @@ from collections import Iterable # [deprecated-class] import collections.Set # [deprecated-class] - -import collections - - -_ = collections.Awaitable() # [deprecated-class] diff --git a/tests/functional/d/deprecated/deprecated_class_py33.rc b/tests/functional/d/deprecated/deprecated_class_py33.rc index 4e2b748313..be3adcd6a9 100644 --- a/tests/functional/d/deprecated/deprecated_class_py33.rc +++ b/tests/functional/d/deprecated/deprecated_class_py33.rc @@ -1,2 +1,2 @@ -[testoptions] -max_pyver=3.10 +[main] +py-version=3.3 diff --git a/tests/functional/d/deprecated/deprecated_class_py33.txt b/tests/functional/d/deprecated/deprecated_class_py33.txt index ea1f8146ee..987c945dd1 100644 --- a/tests/functional/d/deprecated/deprecated_class_py33.txt +++ b/tests/functional/d/deprecated/deprecated_class_py33.txt @@ -1,3 +1,2 @@ deprecated-class:4:0:4:32::Using deprecated class Iterable of module collections:UNDEFINED deprecated-class:6:0:6:22::Using deprecated class Set of module collections:UNDEFINED -deprecated-class:11:4:11:27::Using deprecated class Awaitable of module collections:UNDEFINED diff --git a/tests/functional/d/deprecated/deprecated_methods_py39.rc b/tests/functional/d/deprecated/deprecated_methods_py39.rc index 4e2b748313..77b418f759 100644 --- a/tests/functional/d/deprecated/deprecated_methods_py39.rc +++ b/tests/functional/d/deprecated/deprecated_methods_py39.rc @@ -1,2 +1,2 @@ -[testoptions] -max_pyver=3.10 +[main] +py-version=3.9 diff --git a/tests/functional/d/deprecated/deprecated_module_py39.rc b/tests/functional/d/deprecated/deprecated_module_py39.rc index 4e2b748313..77b418f759 100644 --- a/tests/functional/d/deprecated/deprecated_module_py39.rc +++ b/tests/functional/d/deprecated/deprecated_module_py39.rc @@ -1,2 +1,2 @@ -[testoptions] -max_pyver=3.10 +[main] +py-version=3.9 diff --git a/tests/functional/d/deprecated/deprecated_module_py39_earlier_pyversion.rc b/tests/functional/d/deprecated/deprecated_module_py39_earlier_pyversion.rc index 5dc39b1a65..6f046622fa 100644 --- a/tests/functional/d/deprecated/deprecated_module_py39_earlier_pyversion.rc +++ b/tests/functional/d/deprecated/deprecated_module_py39_earlier_pyversion.rc @@ -1,5 +1,2 @@ [main] py-version=3.8 - -[testoptions] -max_pyver=3.10 diff --git a/tests/functional/i/iterable_context_asyncio.rc b/tests/functional/i/iterable_context_asyncio.rc index 4e2b748313..092b342ea6 100644 --- a/tests/functional/i/iterable_context_asyncio.rc +++ b/tests/functional/i/iterable_context_asyncio.rc @@ -1,2 +1,5 @@ +[main] +py-version=3.9 + [testoptions] -max_pyver=3.10 +max_pyver=3.11 diff --git a/tests/functional/r/regression/regression_4439.py b/tests/functional/r/regression/regression_4439.py index 3dc60cf9c0..e44a40a253 100644 --- a/tests/functional/r/regression/regression_4439.py +++ b/tests/functional/r/regression/regression_4439.py @@ -14,4 +14,4 @@ class User: name: str = attrib() age: int = attrib() - occupation = Optional[str] = attrib(default=None) # [unsupported-assignment-operation] + occupation = Optional[str] = attrib(default=None) diff --git a/tests/functional/r/regression/regression_4439.rc b/tests/functional/r/regression/regression_4439.rc index 4e2b748313..77b418f759 100644 --- a/tests/functional/r/regression/regression_4439.rc +++ b/tests/functional/r/regression/regression_4439.rc @@ -1,2 +1,2 @@ -[testoptions] -max_pyver=3.10 +[main] +py-version=3.9 diff --git a/tests/functional/r/regression/regression_4439.txt b/tests/functional/r/regression/regression_4439.txt deleted file mode 100644 index 6db65057f7..0000000000 --- a/tests/functional/r/regression/regression_4439.txt +++ /dev/null @@ -1 +0,0 @@ -unsupported-assignment-operation:17:17:17:25:User:'Optional' does not support item assignment:UNDEFINED diff --git a/tests/functional/w/wrong_exception_operation_py37.py b/tests/functional/w/wrong_exception_operation_py37.py index 1c3c4e3803..dcc542606a 100644 --- a/tests/functional/w/wrong_exception_operation_py37.py +++ b/tests/functional/w/wrong_exception_operation_py37.py @@ -3,7 +3,7 @@ try: 1/0 -except (ValueError | TypeError): # [wrong-exception-operation] +except (ValueError | TypeError): # [wrong-exception-operation, catching-non-exception] pass try: diff --git a/tests/functional/w/wrong_exception_operation_py37.rc b/tests/functional/w/wrong_exception_operation_py37.rc index 4e2b748313..77b418f759 100644 --- a/tests/functional/w/wrong_exception_operation_py37.rc +++ b/tests/functional/w/wrong_exception_operation_py37.rc @@ -1,2 +1,2 @@ -[testoptions] -max_pyver=3.10 +[main] +py-version=3.9 diff --git a/tests/functional/w/wrong_exception_operation_py37.txt b/tests/functional/w/wrong_exception_operation_py37.txt index c92fcc2a2b..dc3c213462 100644 --- a/tests/functional/w/wrong_exception_operation_py37.txt +++ b/tests/functional/w/wrong_exception_operation_py37.txt @@ -1,3 +1,4 @@ +catching-non-exception:6:8:6:30::"Catching an exception which doesn't inherit from Exception: ValueError | TypeError":UNDEFINED wrong-exception-operation:6:8:6:30::Invalid exception operation. Did you mean '(ValueError, TypeError)' instead?:UNDEFINED wrong-exception-operation:11:8:11:30::Invalid exception operation. Did you mean '(ValueError, TypeError)' instead?:UNDEFINED wrong-exception-operation:17:8:17:30::Invalid exception operation. Did you mean '(ValueError, TypeError)' instead?:UNDEFINED From f8e7e6b1c0721f340b7c9e3bc914d075880039ad Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Mon, 26 May 2025 08:25:54 -0400 Subject: [PATCH 02/15] Remove PY310_PLUS constant --- pylint/checkers/typecheck.py | 5 ++--- pylint/constants.py | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/pylint/checkers/typecheck.py b/pylint/checkers/typecheck.py index 7953e640b4..b684ae4c52 100644 --- a/pylint/checkers/typecheck.py +++ b/pylint/checkers/typecheck.py @@ -49,7 +49,6 @@ supports_membership_test, supports_setitem, ) -from pylint.constants import PY310_PLUS from pylint.interfaces import HIGH, INFERENCE from pylint.typing import MessageDefinitionTuple @@ -796,7 +795,7 @@ def _is_c_extension(module_node: InferenceResult) -> bool: def _is_invalid_isinstance_type(arg: nodes.NodeNG) -> bool: # Return True if we are sure that arg is not a type - if PY310_PLUS and isinstance(arg, nodes.BinOp) and arg.op == "|": + if isinstance(arg, nodes.BinOp) and arg.op == "|": return any( _is_invalid_isinstance_type(elt) and not is_none(elt) for elt in (arg.left, arg.right) @@ -811,7 +810,7 @@ def _is_invalid_isinstance_type(arg: nodes.NodeNG) -> bool: return False if isinstance(inferred, astroid.Instance) and inferred.qname() == BUILTIN_TUPLE: return False - if PY310_PLUS and isinstance(inferred, bases.UnionType): + if isinstance(inferred, bases.UnionType): return any( _is_invalid_isinstance_type(elt) and not is_none(elt) for elt in (inferred.left, inferred.right) diff --git a/pylint/constants.py b/pylint/constants.py index 6911393d37..a5285d1bed 100644 --- a/pylint/constants.py +++ b/pylint/constants.py @@ -14,7 +14,6 @@ from pylint.__pkginfo__ import __version__ from pylint.typing import MessageTypesFullName -PY310_PLUS = sys.version_info[:2] >= (3, 10) PY311_PLUS = sys.version_info[:2] >= (3, 11) PY312_PLUS = sys.version_info[:2] >= (3, 12) PY314_PLUS = sys.version_info[:2] >= (3, 14) From b3556fd4f0545225131026097cafa3a1c0e74420 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Mon, 26 May 2025 08:26:35 -0400 Subject: [PATCH 03/15] Remove version guards from typing imports --- pylint/config/_pylint_config/utils.py | 7 +------ pylint/extensions/code_style.py | 8 +------- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/pylint/config/_pylint_config/utils.py b/pylint/config/_pylint_config/utils.py index 7ed8b83843..54b199394a 100644 --- a/pylint/config/_pylint_config/utils.py +++ b/pylint/config/_pylint_config/utils.py @@ -9,12 +9,7 @@ import sys from collections.abc import Callable from pathlib import Path -from typing import Literal, TypeVar - -if sys.version_info >= (3, 10): - from typing import ParamSpec -else: - from typing_extensions import ParamSpec +from typing import Literal, ParamSpec, TypeVar _P = ParamSpec("_P") _ReturnValueT = TypeVar("_ReturnValueT", bool, str) diff --git a/pylint/extensions/code_style.py b/pylint/extensions/code_style.py index a8c44ec5ed..d187cd7c5c 100644 --- a/pylint/extensions/code_style.py +++ b/pylint/extensions/code_style.py @@ -4,8 +4,7 @@ from __future__ import annotations -import sys -from typing import TYPE_CHECKING, cast +from typing import TYPE_CHECKING, TypeGuard, cast from astroid import nodes @@ -16,11 +15,6 @@ if TYPE_CHECKING: from pylint.lint import PyLinter -if sys.version_info >= (3, 10): - from typing import TypeGuard -else: - from typing_extensions import TypeGuard - class CodeStyleChecker(BaseChecker): """Checkers that can improve code consistency. From a31cbd80912fb5d2fe8c80ec600f4f205f2d5b6c Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Mon, 26 May 2025 08:35:18 -0400 Subject: [PATCH 04/15] Drop support for Python 3.9 --- .github/workflows/primer-test.yaml | 4 ++-- .github/workflows/primer_run_main.yaml | 2 +- .github/workflows/primer_run_pr.yaml | 5 +++-- .github/workflows/tests.yaml | 8 +++----- README.rst | 2 +- doc/whatsnew/fragments/10405.other | 4 ++++ pylintrc | 2 +- pyproject.toml | 3 +-- tests/primer/packages_to_prime.json | 1 - tox.ini | 2 +- 10 files changed, 17 insertions(+), 16 deletions(-) create mode 100644 doc/whatsnew/fragments/10405.other diff --git a/.github/workflows/primer-test.yaml b/.github/workflows/primer-test.yaml index dc3c0942ac..8f7de5a0cf 100644 --- a/.github/workflows/primer-test.yaml +++ b/.github/workflows/primer-test.yaml @@ -30,7 +30,7 @@ jobs: timeout-minutes: 5 strategy: matrix: - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] + python-version: ["3.10", "3.11", "3.12", "3.13"] outputs: python-key: ${{ steps.generate-python-key.outputs.key }} steps: @@ -72,7 +72,7 @@ jobs: needs: prepare-tests-linux strategy: matrix: - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] + python-version: ["3.10", "3.11", "3.12", "3.13"] steps: - name: Check out code from GitHub uses: actions/checkout@v4.2.2 diff --git a/.github/workflows/primer_run_main.yaml b/.github/workflows/primer_run_main.yaml index 2d37943e8d..ccaf207d96 100644 --- a/.github/workflows/primer_run_main.yaml +++ b/.github/workflows/primer_run_main.yaml @@ -29,7 +29,7 @@ jobs: timeout-minutes: 45 strategy: matrix: - python-version: ["3.9", "3.13"] + python-version: ["3.10", "3.13"] batches: [4] batchIdx: [0, 1, 2, 3] steps: diff --git a/.github/workflows/primer_run_pr.yaml b/.github/workflows/primer_run_pr.yaml index f2bd5b563f..0e0eafd26f 100644 --- a/.github/workflows/primer_run_pr.yaml +++ b/.github/workflows/primer_run_pr.yaml @@ -38,7 +38,7 @@ jobs: timeout-minutes: 45 strategy: matrix: - python-version: ["3.9", "3.13"] + python-version: ["3.10", "3.13"] batches: [4] batchIdx: [0, 1, 2, 3] steps: @@ -217,7 +217,8 @@ jobs: echo ${{ github.event.pull_request.number }} | tee pr_number.txt - name: Upload PR number if: - startsWith(steps.python.outputs.python-version, '3.9') && matrix.batchIdx == 0 + startsWith(steps.python.outputs.python-version, '3.10') && matrix.batchIdx == + 0 uses: actions/upload-artifact@v4.6.2 with: name: pr_number diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 43ea67586a..c99707fa26 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -31,12 +31,10 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] + python-version: ["3.10", "3.11", "3.12", "3.13"] include: - os: macos-latest - python-version: "3.9" - - os: ubuntu-latest - python-version: "pypy-3.9" + python-version: "3.10" - os: ubuntu-latest python-version: "pypy-3.10" - os: ubuntu-latest @@ -190,7 +188,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] + python-version: ["3.10", "3.11", "3.12", "3.13"] steps: - name: Set temp directory run: echo "TEMP=$env:USERPROFILE\AppData\Local\Temp" >> $env:GITHUB_ENV diff --git a/README.rst b/README.rst index 76134f428c..a4f22ef58d 100644 --- a/README.rst +++ b/README.rst @@ -45,7 +45,7 @@ What is Pylint? --------------- Pylint is a `static code analyser`_ for Python 2 or 3. The latest version supports Python -3.9.0 and above. +3.10.0 and above. .. _`static code analyser`: https://en.wikipedia.org/wiki/Static_code_analysis diff --git a/doc/whatsnew/fragments/10405.other b/doc/whatsnew/fragments/10405.other new file mode 100644 index 0000000000..0bdaa73042 --- /dev/null +++ b/doc/whatsnew/fragments/10405.other @@ -0,0 +1,4 @@ +Remove support for launching pylint with Python 3.9. +Code that supports Python 3.9 can still be linted with the ``--py-version=3.9`` setting. + +Refs #10405 diff --git a/pylintrc b/pylintrc index 6ccfa56650..fe653a092c 100644 --- a/pylintrc +++ b/pylintrc @@ -50,7 +50,7 @@ unsafe-load-any-extension=no extension-pkg-allow-list= # Minimum supported python version -py-version = 3.9.0 +py-version = 3.10.0 # Control the amount of potential inferred values when inferring a single # object. This can help the performance when dealing with large functions or diff --git a/pyproject.toml b/pyproject.toml index 3b2a60f906..36cd044712 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,7 @@ license-files = [ "LICENSE", "CONTRIBUTORS.txt" ] authors = [ { name = "Python Code Quality Authority", email = "code-quality@python.org" }, ] -requires-python = ">=3.9.0" +requires-python = ">=3.10.0" classifiers = [ "Development Status :: 6 - Mature", "Environment :: Console", @@ -21,7 +21,6 @@ classifiers = [ "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", diff --git a/tests/primer/packages_to_prime.json b/tests/primer/packages_to_prime.json index a0d1b38c0c..8e76cf37ed 100644 --- a/tests/primer/packages_to_prime.json +++ b/tests/primer/packages_to_prime.json @@ -29,7 +29,6 @@ "branch": "master", "directories": ["music21"], "pylintrc_relpath": ".pylintrc", - "minimum_python": "3.10", "url": "https://github.com/cuthbertLab/music21" }, "pandas": { diff --git a/tox.ini b/tox.ini index b5730ea9e3..a77a63ab23 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.0 -envlist = formatting, py39, py310, py311, py312, py313, pypy, benchmark +envlist = formatting, py310, py311, py312, py313, pypy, benchmark skip_missing_interpreters = true requires = pip >=21.3.1 isolated_build = true From 66470067e058de44c1dbf7f9bf690a9fb8931a84 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Mon, 26 May 2025 08:37:55 -0400 Subject: [PATCH 05/15] Remove min_pyver=3.10 --- tests/functional/a/alternative/alternative_union_syntax.rc | 3 --- .../a/alternative/alternative_union_syntax_regession_8119.rc | 2 -- tests/functional/d/dataclass/dataclass_kw_only.rc | 2 -- tests/functional/d/dataclass/dataclass_parameter.rc | 2 -- .../functional/ext/typing/redundant_typehint_argument_py310.rc | 3 --- .../functional/ext/typing/typing_consider_using_union_py310.rc | 3 --- tests/functional/i/isinstance_second_argument_py310.rc | 2 -- tests/functional/p/pattern_matching.rc | 2 -- .../s/super/super_init_not_called_extensions_py310.rc | 1 - tests/functional/t/type/typealias_naming_style_default.rc | 2 -- tests/functional/t/type/typealias_naming_style_rgx.rc | 3 --- tests/functional/u/unpacking/unpacking_non_sequence_py310.rc | 2 -- .../unused_name_in_string_literal_type_annotation_py310.rc | 2 -- tests/functional/u/used/used_before_assignment_py310.rc | 2 -- tests/functional/w/wrong_exception_operation.rc | 2 -- 15 files changed, 33 deletions(-) delete mode 100644 tests/functional/a/alternative/alternative_union_syntax_regession_8119.rc delete mode 100644 tests/functional/d/dataclass/dataclass_kw_only.rc delete mode 100644 tests/functional/d/dataclass/dataclass_parameter.rc delete mode 100644 tests/functional/i/isinstance_second_argument_py310.rc delete mode 100644 tests/functional/p/pattern_matching.rc delete mode 100644 tests/functional/t/type/typealias_naming_style_default.rc delete mode 100644 tests/functional/u/unpacking/unpacking_non_sequence_py310.rc delete mode 100644 tests/functional/u/unused/unused_name_in_string_literal_type_annotation_py310.rc delete mode 100644 tests/functional/u/used/used_before_assignment_py310.rc delete mode 100644 tests/functional/w/wrong_exception_operation.rc diff --git a/tests/functional/a/alternative/alternative_union_syntax.rc b/tests/functional/a/alternative/alternative_union_syntax.rc index b8ab9047ad..d36622d880 100644 --- a/tests/functional/a/alternative/alternative_union_syntax.rc +++ b/tests/functional/a/alternative/alternative_union_syntax.rc @@ -1,5 +1,2 @@ [main] py-version=3.10 - -[testoptions] -min_pyver=3.10 diff --git a/tests/functional/a/alternative/alternative_union_syntax_regession_8119.rc b/tests/functional/a/alternative/alternative_union_syntax_regession_8119.rc deleted file mode 100644 index 68a8c8ef15..0000000000 --- a/tests/functional/a/alternative/alternative_union_syntax_regession_8119.rc +++ /dev/null @@ -1,2 +0,0 @@ -[testoptions] -min_pyver=3.10 diff --git a/tests/functional/d/dataclass/dataclass_kw_only.rc b/tests/functional/d/dataclass/dataclass_kw_only.rc deleted file mode 100644 index 68a8c8ef15..0000000000 --- a/tests/functional/d/dataclass/dataclass_kw_only.rc +++ /dev/null @@ -1,2 +0,0 @@ -[testoptions] -min_pyver=3.10 diff --git a/tests/functional/d/dataclass/dataclass_parameter.rc b/tests/functional/d/dataclass/dataclass_parameter.rc deleted file mode 100644 index 68a8c8ef15..0000000000 --- a/tests/functional/d/dataclass/dataclass_parameter.rc +++ /dev/null @@ -1,2 +0,0 @@ -[testoptions] -min_pyver=3.10 diff --git a/tests/functional/ext/typing/redundant_typehint_argument_py310.rc b/tests/functional/ext/typing/redundant_typehint_argument_py310.rc index 3c06fa4330..63e11a4e6b 100644 --- a/tests/functional/ext/typing/redundant_typehint_argument_py310.rc +++ b/tests/functional/ext/typing/redundant_typehint_argument_py310.rc @@ -1,6 +1,3 @@ [main] py-version=3.10 load-plugins=pylint.extensions.typing - -[testoptions] -min_pyver=3.10 diff --git a/tests/functional/ext/typing/typing_consider_using_union_py310.rc b/tests/functional/ext/typing/typing_consider_using_union_py310.rc index a35db15773..55c07d76e4 100644 --- a/tests/functional/ext/typing/typing_consider_using_union_py310.rc +++ b/tests/functional/ext/typing/typing_consider_using_union_py310.rc @@ -2,7 +2,4 @@ py-version=3.10 load-plugins=pylint.extensions.typing -[testoptions] -min_pyver=3.10 - [typing] diff --git a/tests/functional/i/isinstance_second_argument_py310.rc b/tests/functional/i/isinstance_second_argument_py310.rc deleted file mode 100644 index 68a8c8ef15..0000000000 --- a/tests/functional/i/isinstance_second_argument_py310.rc +++ /dev/null @@ -1,2 +0,0 @@ -[testoptions] -min_pyver=3.10 diff --git a/tests/functional/p/pattern_matching.rc b/tests/functional/p/pattern_matching.rc deleted file mode 100644 index 68a8c8ef15..0000000000 --- a/tests/functional/p/pattern_matching.rc +++ /dev/null @@ -1,2 +0,0 @@ -[testoptions] -min_pyver=3.10 diff --git a/tests/functional/s/super/super_init_not_called_extensions_py310.rc b/tests/functional/s/super/super_init_not_called_extensions_py310.rc index 3ab4e08e91..e73859088c 100644 --- a/tests/functional/s/super/super_init_not_called_extensions_py310.rc +++ b/tests/functional/s/super/super_init_not_called_extensions_py310.rc @@ -1,4 +1,3 @@ [testoptions] # Windows test environments on >= 3.10 don't have typing_extensions exclude_platforms=win32 -min_pyver=3.10 diff --git a/tests/functional/t/type/typealias_naming_style_default.rc b/tests/functional/t/type/typealias_naming_style_default.rc deleted file mode 100644 index 68a8c8ef15..0000000000 --- a/tests/functional/t/type/typealias_naming_style_default.rc +++ /dev/null @@ -1,2 +0,0 @@ -[testoptions] -min_pyver=3.10 diff --git a/tests/functional/t/type/typealias_naming_style_rgx.rc b/tests/functional/t/type/typealias_naming_style_rgx.rc index 2521a50b36..508ef15b7d 100644 --- a/tests/functional/t/type/typealias_naming_style_rgx.rc +++ b/tests/functional/t/type/typealias_naming_style_rgx.rc @@ -1,5 +1,2 @@ [BASIC] typealias-rgx=_{0,2}TypeAliasShouldBeLikeThis - -[testoptions] -min_pyver=3.10 diff --git a/tests/functional/u/unpacking/unpacking_non_sequence_py310.rc b/tests/functional/u/unpacking/unpacking_non_sequence_py310.rc deleted file mode 100644 index 68a8c8ef15..0000000000 --- a/tests/functional/u/unpacking/unpacking_non_sequence_py310.rc +++ /dev/null @@ -1,2 +0,0 @@ -[testoptions] -min_pyver=3.10 diff --git a/tests/functional/u/unused/unused_name_in_string_literal_type_annotation_py310.rc b/tests/functional/u/unused/unused_name_in_string_literal_type_annotation_py310.rc deleted file mode 100644 index 68a8c8ef15..0000000000 --- a/tests/functional/u/unused/unused_name_in_string_literal_type_annotation_py310.rc +++ /dev/null @@ -1,2 +0,0 @@ -[testoptions] -min_pyver=3.10 diff --git a/tests/functional/u/used/used_before_assignment_py310.rc b/tests/functional/u/used/used_before_assignment_py310.rc deleted file mode 100644 index 68a8c8ef15..0000000000 --- a/tests/functional/u/used/used_before_assignment_py310.rc +++ /dev/null @@ -1,2 +0,0 @@ -[testoptions] -min_pyver=3.10 diff --git a/tests/functional/w/wrong_exception_operation.rc b/tests/functional/w/wrong_exception_operation.rc deleted file mode 100644 index 68a8c8ef15..0000000000 --- a/tests/functional/w/wrong_exception_operation.rc +++ /dev/null @@ -1,2 +0,0 @@ -[testoptions] -min_pyver=3.10 From 207eb0ef20eaa865e6a4509f6b06fdb652e2ebea Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 26 May 2025 13:33:22 +0000 Subject: [PATCH 06/15] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pylint/checkers/imports.py | 4 ++-- pylint/extensions/mccabe.py | 2 +- pylint/pyreverse/inspector.py | 3 +-- pylint/pyreverse/utils.py | 6 +++--- pylint/reporters/json_reporter.py | 6 +++--- pylint/typing.py | 23 ++++++++++------------- 6 files changed, 20 insertions(+), 24 deletions(-) diff --git a/pylint/checkers/imports.py b/pylint/checkers/imports.py index fa63ea9dfb..83435efabd 100644 --- a/pylint/checkers/imports.py +++ b/pylint/checkers/imports.py @@ -13,7 +13,7 @@ from collections import defaultdict from collections.abc import ItemsView, Sequence from functools import cached_property -from typing import TYPE_CHECKING, Any, Union +from typing import TYPE_CHECKING, Any import astroid from astroid import nodes @@ -43,7 +43,7 @@ # The dictionary with Any should actually be a _ImportTree again # but mypy doesn't support recursive types yet -_ImportTree = dict[str, Union[list[dict[str, Any]], list[str]]] +_ImportTree = dict[str, list[dict[str, Any]] | list[str]] DEPRECATED_MODULES = { (0, 0, 0): {"tkinter.tix", "fpectl"}, diff --git a/pylint/extensions/mccabe.py b/pylint/extensions/mccabe.py index 9489f24d6c..e60c0b15f6 100644 --- a/pylint/extensions/mccabe.py +++ b/pylint/extensions/mccabe.py @@ -41,7 +41,7 @@ _SubGraphNodes = Union[nodes.If, nodes.Try, nodes.For, nodes.While] _AppendableNodeT = TypeVar( - "_AppendableNodeT", bound=Union[_StatementNodes, nodes.While, nodes.FunctionDef] + "_AppendableNodeT", bound=_StatementNodes | nodes.While | nodes.FunctionDef ) diff --git a/pylint/pyreverse/inspector.py b/pylint/pyreverse/inspector.py index 8e69e94470..aff15909ac 100644 --- a/pylint/pyreverse/inspector.py +++ b/pylint/pyreverse/inspector.py @@ -14,7 +14,6 @@ import traceback from abc import ABC, abstractmethod from collections.abc import Callable, Sequence -from typing import Optional import astroid from astroid import nodes @@ -24,7 +23,7 @@ from pylint.pyreverse import utils _WrapperFuncT = Callable[ - [Callable[[str], nodes.Module], str, bool], Optional[nodes.Module] + [Callable[[str], nodes.Module], str, bool], nodes.Module | None ] diff --git a/pylint/pyreverse/utils.py b/pylint/pyreverse/utils.py index 5ad92d3231..4ec4052353 100644 --- a/pylint/pyreverse/utils.py +++ b/pylint/pyreverse/utils.py @@ -12,7 +12,7 @@ import subprocess import sys from collections.abc import Callable -from typing import TYPE_CHECKING, Any, Optional, Union +from typing import TYPE_CHECKING, Any import astroid from astroid import nodes @@ -23,9 +23,9 @@ _CallbackT = Callable[ [nodes.NodeNG], - Union[tuple[ClassDiagram], tuple[PackageDiagram, ClassDiagram], None], + tuple[ClassDiagram] | tuple[PackageDiagram, ClassDiagram] | None, ] - _CallbackTupleT = tuple[Optional[_CallbackT], Optional[_CallbackT]] + _CallbackTupleT = tuple[_CallbackT | None, _CallbackT | None] RCFILE = ".pyreverserc" diff --git a/pylint/reporters/json_reporter.py b/pylint/reporters/json_reporter.py index 7135dfc66c..d5f847cd9b 100644 --- a/pylint/reporters/json_reporter.py +++ b/pylint/reporters/json_reporter.py @@ -7,7 +7,7 @@ from __future__ import annotations import json -from typing import TYPE_CHECKING, Optional, TypedDict +from typing import TYPE_CHECKING, TypedDict from pylint.interfaces import CONFIDENCE_MAP, UNDEFINED from pylint.message import Message @@ -27,8 +27,8 @@ "obj": str, "line": int, "column": int, - "endLine": Optional[int], - "endColumn": Optional[int], + "endLine": int | None, + "endColumn": int | None, "path": str, "symbol": str, "message": str, diff --git a/pylint/typing.py b/pylint/typing.py index a43674d249..eb55f59468 100644 --- a/pylint/typing.py +++ b/pylint/typing.py @@ -7,13 +7,12 @@ from __future__ import annotations import argparse -from collections.abc import Iterable, Sequence +from collections.abc import Callable, Iterable, Sequence from pathlib import Path from re import Pattern from typing import ( TYPE_CHECKING, Any, - Callable, Literal, NamedTuple, Optional, @@ -95,17 +94,15 @@ class ManagedMessage(NamedTuple): OptionDict = dict[ str, - Union[ - None, - str, - bool, - int, - Pattern[str], - Iterable[Union[str, int, Pattern[str]]], - type["_CallbackAction"], - Callable[[Any], Any], - Callable[[Any, Any, Any, Any], Any], - ], + None + | str + | bool + | int + | Pattern[str] + | Iterable[str | int | Pattern[str]] + | type["_CallbackAction"] + | Callable[[Any], Any] + | Callable[[Any, Any, Any, Any], Any], ] Options = tuple[tuple[str, OptionDict], ...] From 8aaea5bfd7e613555f46ad6d648d82b09bbfb332 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Mon, 26 May 2025 11:26:43 -0400 Subject: [PATCH 07/15] Update functional test output --- .../a/alternative/alternative_union_syntax_error.txt | 2 -- tests/functional/d/deprecated/deprecated_methods_py39.py | 4 ---- tests/functional/d/deprecated/deprecated_methods_py39.rc | 2 -- tests/functional/d/deprecated/deprecated_methods_py39.txt | 1 - tests/functional/d/deprecated/deprecated_module_py39.py | 2 +- tests/functional/d/deprecated/deprecated_module_py39.txt | 1 + .../d/deprecated/deprecated_module_py39_earlier_pyversion.py | 2 +- .../d/deprecated/deprecated_module_py39_earlier_pyversion.txt | 1 + 8 files changed, 4 insertions(+), 11 deletions(-) delete mode 100644 tests/functional/d/deprecated/deprecated_methods_py39.py delete mode 100644 tests/functional/d/deprecated/deprecated_methods_py39.rc delete mode 100644 tests/functional/d/deprecated/deprecated_methods_py39.txt diff --git a/tests/functional/a/alternative/alternative_union_syntax_error.txt b/tests/functional/a/alternative/alternative_union_syntax_error.txt index 6f4c19a4e4..8bc7dcd533 100644 --- a/tests/functional/a/alternative/alternative_union_syntax_error.txt +++ b/tests/functional/a/alternative/alternative_union_syntax_error.txt @@ -1,8 +1,6 @@ unsupported-binary-operation:22:8:22:30::unsupported operand type(s) for |:INFERENCE unsupported-binary-operation:23:7:23:35::unsupported operand type(s) for |:INFERENCE unsupported-binary-operation:25:23:25:33::unsupported operand type(s) for |:INFERENCE -unsupported-binary-operation:26:6:26:22::unsupported operand type(s) for |:INFERENCE -unsupported-binary-operation:26:6:26:15::unsupported operand type(s) for |:INFERENCE unsupported-binary-operation:27:6:27:34::unsupported operand type(s) for |:INFERENCE unsupported-binary-operation:28:18:28:46::unsupported operand type(s) for |:INFERENCE unsupported-binary-operation:31:23:31:32::unsupported operand type(s) for |:INFERENCE diff --git a/tests/functional/d/deprecated/deprecated_methods_py39.py b/tests/functional/d/deprecated/deprecated_methods_py39.py deleted file mode 100644 index 9959b1c2a2..0000000000 --- a/tests/functional/d/deprecated/deprecated_methods_py39.py +++ /dev/null @@ -1,4 +0,0 @@ -"""Test deprecated methods from Python 3.9.""" - -import binascii -binascii.b2a_hqx() # [deprecated-method] diff --git a/tests/functional/d/deprecated/deprecated_methods_py39.rc b/tests/functional/d/deprecated/deprecated_methods_py39.rc deleted file mode 100644 index 77b418f759..0000000000 --- a/tests/functional/d/deprecated/deprecated_methods_py39.rc +++ /dev/null @@ -1,2 +0,0 @@ -[main] -py-version=3.9 diff --git a/tests/functional/d/deprecated/deprecated_methods_py39.txt b/tests/functional/d/deprecated/deprecated_methods_py39.txt deleted file mode 100644 index 292ca5ef16..0000000000 --- a/tests/functional/d/deprecated/deprecated_methods_py39.txt +++ /dev/null @@ -1 +0,0 @@ -deprecated-method:4:0:4:18::Using deprecated method b2a_hqx():UNDEFINED diff --git a/tests/functional/d/deprecated/deprecated_module_py39.py b/tests/functional/d/deprecated/deprecated_module_py39.py index a897dd4e33..8f1ef8c5e0 100644 --- a/tests/functional/d/deprecated/deprecated_module_py39.py +++ b/tests/functional/d/deprecated/deprecated_module_py39.py @@ -1,4 +1,4 @@ """Test deprecated modules from Python 3.9.""" # pylint: disable=unused-import -import binhex # [deprecated-module] +import binhex # [deprecated-module, import-error] diff --git a/tests/functional/d/deprecated/deprecated_module_py39.txt b/tests/functional/d/deprecated/deprecated_module_py39.txt index b3ee13c050..c584213291 100644 --- a/tests/functional/d/deprecated/deprecated_module_py39.txt +++ b/tests/functional/d/deprecated/deprecated_module_py39.txt @@ -1 +1,2 @@ deprecated-module:4:0:4:13::Deprecated module 'binhex':UNDEFINED +import-error:4:0:4:13::Unable to import 'binhex':UNDEFINED diff --git a/tests/functional/d/deprecated/deprecated_module_py39_earlier_pyversion.py b/tests/functional/d/deprecated/deprecated_module_py39_earlier_pyversion.py index c1c2f17883..4b15907cf4 100644 --- a/tests/functional/d/deprecated/deprecated_module_py39_earlier_pyversion.py +++ b/tests/functional/d/deprecated/deprecated_module_py39_earlier_pyversion.py @@ -3,4 +3,4 @@ """ # pylint: disable=unused-import -import binhex # [deprecated-module] +import binhex # [deprecated-module, import-error] diff --git a/tests/functional/d/deprecated/deprecated_module_py39_earlier_pyversion.txt b/tests/functional/d/deprecated/deprecated_module_py39_earlier_pyversion.txt index 3ddb6b21d0..d079403287 100644 --- a/tests/functional/d/deprecated/deprecated_module_py39_earlier_pyversion.txt +++ b/tests/functional/d/deprecated/deprecated_module_py39_earlier_pyversion.txt @@ -1 +1,2 @@ deprecated-module:6:0:6:13::Deprecated module 'binhex':UNDEFINED +import-error:6:0:6:13::Unable to import 'binhex':UNDEFINED From 212ed1b0d38cfc2aed06b77144f4f0b93c80e231 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Mon, 26 May 2025 11:45:13 -0400 Subject: [PATCH 08/15] Replace zip() with itertools.pairwise() --- pylint/checkers/base/basic_checker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pylint/checkers/base/basic_checker.py b/pylint/checkers/base/basic_checker.py index 56400cbead..68cf2c4327 100644 --- a/pylint/checkers/base/basic_checker.py +++ b/pylint/checkers/base/basic_checker.py @@ -884,7 +884,7 @@ def visit_with(self, node: nodes.With) -> None: # to one AST "With" node with multiple items pairs = node.items if pairs: - for prev_pair, pair in zip(pairs, pairs[1:]): + for prev_pair, pair in itertools.pairwise(pairs): if isinstance(prev_pair[1], nodes.AssignName) and ( pair[1] is None and not isinstance(pair[0], nodes.Call) ): From f7048d3bea12a9cc80830059164e23063b5d013f Mon Sep 17 00:00:00 2001 From: Pierre Sassoulas Date: Mon, 26 May 2025 23:03:51 +0200 Subject: [PATCH 09/15] Configure ruff for python 3.10 --- pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 36cd044712..9255aac69e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,6 +86,8 @@ version = { attr = "pylint.__pkginfo__.__version__" } # (for docstrings, strings and comments in particular). line-length = 115 +target-version = "py310" + extend-exclude = [ "tests/**/data/", "tests/**/functional/", From 7caee17b8849ca8de9c1eec5f09b83d440ffde34 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 26 May 2025 21:04:46 +0000 Subject: [PATCH 10/15] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 9255aac69e..8ce2fad605 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -82,12 +82,12 @@ version = { attr = "pylint.__pkginfo__.__version__" } [tool.ruff] +target-version = "py310" + # ruff is less lenient than pylint and does not make any exceptions # (for docstrings, strings and comments in particular). line-length = 115 -target-version = "py310" - extend-exclude = [ "tests/**/data/", "tests/**/functional/", From 2c2395876c91f134ce93034061acbd1971e6edd9 Mon Sep 17 00:00:00 2001 From: Pierre Sassoulas Date: Tue, 27 May 2025 13:04:37 +0200 Subject: [PATCH 11/15] Update pyproject.toml Co-authored-by: Jacob Walls --- pyproject.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8ce2fad605..36cd044712 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -82,8 +82,6 @@ version = { attr = "pylint.__pkginfo__.__version__" } [tool.ruff] -target-version = "py310" - # ruff is less lenient than pylint and does not make any exceptions # (for docstrings, strings and comments in particular). line-length = 115 From 7487a2683291dab4951ab10afb0315e599848805 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Tue, 27 May 2025 07:16:54 -0400 Subject: [PATCH 12/15] Ignore UP038 --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 36cd044712..641981ecde 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -136,6 +136,7 @@ lint.ignore = [ "PTH207", # Replace `glob` with `Path.glob` or `Path.rglob` "PTH208", # Use `pathlib.Path.iterdir()` instead" "RUF012", # mutable default values in class attributes + "UP038", # Use `X | Y` in `isinstance` call instead of `(X, Y)` ] lint.pydocstyle.convention = "pep257" From a2edf7a2bbab9c476d769182dfff9d02d889298b Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Tue, 27 May 2025 07:36:53 -0400 Subject: [PATCH 13/15] Fix unittest import --- pylint/testutils/configuration_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pylint/testutils/configuration_test.py b/pylint/testutils/configuration_test.py index ce2239e5c2..93a812659a 100644 --- a/pylint/testutils/configuration_test.py +++ b/pylint/testutils/configuration_test.py @@ -9,7 +9,7 @@ import copy import json import logging -import unittest +import unittest.mock from pathlib import Path from typing import Any From b414c1f0b02797b6ab165d71e1cf85eb0f78adc5 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Tue, 27 May 2025 07:46:13 -0400 Subject: [PATCH 14/15] Fix UP007 --- pylint/checkers/classes/class_checker.py | 4 +- .../refactoring/refactoring_checker.py | 4 +- pylint/checkers/symilar.py | 4 +- pylint/checkers/typecheck.py | 16 +++---- pylint/config/argument.py | 22 +++++----- pylint/extensions/mccabe.py | 42 +++++++++---------- pylint/typing.py | 11 ++--- pylint/utils/utils.py | 18 ++++---- 8 files changed, 59 insertions(+), 62 deletions(-) diff --git a/pylint/checkers/classes/class_checker.py b/pylint/checkers/classes/class_checker.py index b493a1ba73..133ab16584 100644 --- a/pylint/checkers/classes/class_checker.py +++ b/pylint/checkers/classes/class_checker.py @@ -11,7 +11,7 @@ from functools import cached_property from itertools import chain, zip_longest from re import Pattern -from typing import TYPE_CHECKING, Any, NamedTuple, Union +from typing import TYPE_CHECKING, Any, NamedTuple, TypeAlias import astroid from astroid import bases, nodes, util @@ -46,7 +46,7 @@ from pylint.lint.pylinter import PyLinter -_AccessNodes = Union[nodes.Attribute, nodes.AssignAttr] +_AccessNodes: TypeAlias = nodes.Attribute | nodes.AssignAttr INVALID_BASE_CLASSES = {"bool", "range", "slice", "memoryview"} ALLOWED_PROPERTIES = {"bultins.property", "functools.cached_property"} diff --git a/pylint/checkers/refactoring/refactoring_checker.py b/pylint/checkers/refactoring/refactoring_checker.py index 08e5c3491f..e277da9dc1 100644 --- a/pylint/checkers/refactoring/refactoring_checker.py +++ b/pylint/checkers/refactoring/refactoring_checker.py @@ -11,7 +11,7 @@ from collections.abc import Iterator from functools import cached_property, reduce from re import Pattern -from typing import TYPE_CHECKING, Any, NamedTuple, Union, cast +from typing import TYPE_CHECKING, Any, NamedTuple, TypeAlias, cast import astroid from astroid import bases, nodes @@ -27,7 +27,7 @@ from pylint.lint import PyLinter -NodesWithNestedBlocks = Union[nodes.Try, nodes.While, nodes.For, nodes.If] +NodesWithNestedBlocks: TypeAlias = nodes.Try | nodes.While | nodes.For | nodes.If KNOWN_INFINITE_ITERATORS = {"itertools.count", "itertools.cycle"} BUILTIN_EXIT_FUNCS = frozenset(("quit", "exit")) diff --git a/pylint/checkers/symilar.py b/pylint/checkers/symilar.py index 21d22529d6..5b3ff046c3 100644 --- a/pylint/checkers/symilar.py +++ b/pylint/checkers/symilar.py @@ -41,7 +41,7 @@ from collections.abc import Callable, Generator, Iterable, Sequence from io import BufferedIOBase, BufferedReader, BytesIO from itertools import chain -from typing import TYPE_CHECKING, NamedTuple, NewType, NoReturn, TextIO, Union +from typing import TYPE_CHECKING, NamedTuple, NewType, NoReturn, TextIO, TypeAlias import astroid from astroid import nodes @@ -79,7 +79,7 @@ class LineSpecifs(NamedTuple): IndexToLines_T = dict[Index, "SuccessiveLinesLimits"] # The types the streams read by pylint can take. Originating from astroid.nodes.Module.stream() and open() -STREAM_TYPES = Union[TextIO, BufferedReader, BytesIO] +STREAM_TYPES: TypeAlias = TextIO | BufferedReader | BytesIO class CplSuccessiveLinesLimits: diff --git a/pylint/checkers/typecheck.py b/pylint/checkers/typecheck.py index b684ae4c52..e9c5e0140a 100644 --- a/pylint/checkers/typecheck.py +++ b/pylint/checkers/typecheck.py @@ -15,7 +15,7 @@ from collections.abc import Callable, Iterable from functools import cached_property, lru_cache, singledispatch from re import Pattern -from typing import TYPE_CHECKING, Any, Literal, Union +from typing import TYPE_CHECKING, Any, Literal, TypeAlias import astroid import astroid.exceptions @@ -55,13 +55,13 @@ if TYPE_CHECKING: from pylint.lint import PyLinter -CallableObjects = Union[ - bases.BoundMethod, - bases.UnboundMethod, - nodes.FunctionDef, - nodes.Lambda, - nodes.ClassDef, -] +CallableObjects: TypeAlias = ( + bases.BoundMethod + | bases.UnboundMethod + | nodes.FunctionDef + | nodes.Lambda + | nodes.ClassDef +) STR_FORMAT = {"builtins.str.format"} ASYNCIO_COROUTINE = "asyncio.coroutines.coroutine" diff --git a/pylint/config/argument.py b/pylint/config/argument.py index a515a942b4..a604d978aa 100644 --- a/pylint/config/argument.py +++ b/pylint/config/argument.py @@ -16,23 +16,23 @@ from collections.abc import Callable, Sequence from glob import glob from re import Pattern -from typing import Any, Literal, Union +from typing import Any, Literal from pylint import interfaces from pylint import utils as pylint_utils from pylint.config.callback_actions import _CallbackAction from pylint.config.deprecation_actions import _NewNamesAction, _OldNamesAction -_ArgumentTypes = Union[ - str, - int, - float, - bool, - Pattern[str], - Sequence[str], - Sequence[Pattern[str]], - tuple[int, ...], -] +_ArgumentTypes = ( + str + | int + | float + | bool + | Pattern[str] + | Sequence[str] + | Sequence[Pattern[str]] + | tuple[int, ...] +) """List of possible argument types.""" diff --git a/pylint/extensions/mccabe.py b/pylint/extensions/mccabe.py index e60c0b15f6..45bd35cee6 100644 --- a/pylint/extensions/mccabe.py +++ b/pylint/extensions/mccabe.py @@ -7,7 +7,7 @@ from __future__ import annotations from collections.abc import Sequence -from typing import TYPE_CHECKING, Any, TypeVar, Union +from typing import TYPE_CHECKING, Any, TypeAlias, TypeVar from astroid import nodes from mccabe import PathGraph as Mccabe_PathGraph @@ -20,26 +20,26 @@ if TYPE_CHECKING: from pylint.lint import PyLinter -_StatementNodes = Union[ - nodes.Assert, - nodes.Assign, - nodes.AugAssign, - nodes.Delete, - nodes.Raise, - nodes.Yield, - nodes.Import, - nodes.Call, - nodes.Subscript, - nodes.Pass, - nodes.Continue, - nodes.Break, - nodes.Global, - nodes.Return, - nodes.Expr, - nodes.Await, -] - -_SubGraphNodes = Union[nodes.If, nodes.Try, nodes.For, nodes.While] +_StatementNodes: TypeAlias = ( + nodes.Assert + | nodes.Assign + | nodes.AugAssign + | nodes.Delete + | nodes.Raise + | nodes.Yield + | nodes.Import + | nodes.Call + | nodes.Subscript + | nodes.Pass + | nodes.Continue + | nodes.Break + | nodes.Global + | nodes.Return + | nodes.Expr + | nodes.Await +) + +_SubGraphNodes: TypeAlias = nodes.If | nodes.Try | nodes.For | nodes.While _AppendableNodeT = TypeVar( "_AppendableNodeT", bound=_StatementNodes | nodes.While | nodes.FunctionDef ) diff --git a/pylint/typing.py b/pylint/typing.py index eb55f59468..5c59120324 100644 --- a/pylint/typing.py +++ b/pylint/typing.py @@ -15,10 +15,8 @@ Any, Literal, NamedTuple, - Optional, Protocol, TypedDict, - Union, ) if TYPE_CHECKING: @@ -107,7 +105,7 @@ class ManagedMessage(NamedTuple): Options = tuple[tuple[str, OptionDict], ...] -ReportsCallable = Callable[["Section", "LinterStats", Optional["LinterStats"]], None] +ReportsCallable = Callable[["Section", "LinterStats", "LinterStats | None"], None] """Callable to create a report.""" @@ -122,10 +120,9 @@ class ExtraMessageOptions(TypedDict, total=False): default_enabled: bool -MessageDefinitionTuple = Union[ - tuple[str, str, str], - tuple[str, str, str, ExtraMessageOptions], -] +MessageDefinitionTuple = ( + tuple[str, str, str] | tuple[str, str, str, ExtraMessageOptions] +) DirectoryNamespaceDict = dict[Path, tuple[argparse.Namespace, "DirectoryNamespaceDict"]] diff --git a/pylint/utils/utils.py b/pylint/utils/utils.py index 341a4aec6d..b32908307e 100644 --- a/pylint/utils/utils.py +++ b/pylint/utils/utils.py @@ -26,7 +26,7 @@ from collections.abc import Iterable, Sequence from io import BufferedReader, BytesIO from re import Pattern -from typing import TYPE_CHECKING, Any, Literal, TextIO, TypeVar, Union +from typing import TYPE_CHECKING, Any, Literal, TextIO, TypeVar from astroid import Module, modutils, nodes @@ -54,14 +54,14 @@ ] GLOBAL_OPTION_PATTERN_LIST = Literal["exclude-too-few-public-methods", "ignore-paths"] GLOBAL_OPTION_TUPLE_INT = Literal["py-version"] -GLOBAL_OPTION_NAMES = Union[ - GLOBAL_OPTION_BOOL, - GLOBAL_OPTION_INT, - GLOBAL_OPTION_LIST, - GLOBAL_OPTION_PATTERN, - GLOBAL_OPTION_PATTERN_LIST, - GLOBAL_OPTION_TUPLE_INT, -] +GLOBAL_OPTION_NAMES = ( + GLOBAL_OPTION_BOOL + | GLOBAL_OPTION_INT + | GLOBAL_OPTION_LIST + | GLOBAL_OPTION_PATTERN + | GLOBAL_OPTION_PATTERN_LIST + | GLOBAL_OPTION_TUPLE_INT +) T_GlobalOptionReturnTypes = TypeVar( "T_GlobalOptionReturnTypes", bool, From 38c82af1d82b054b890147677048a2c9e9a439c5 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Tue, 27 May 2025 08:10:45 -0400 Subject: [PATCH 15/15] Disable import-error in deprecated module tests --- tests/functional/d/deprecated/deprecated_module_py39.py | 4 ++-- tests/functional/d/deprecated/deprecated_module_py39.txt | 1 - .../d/deprecated/deprecated_module_py39_earlier_pyversion.py | 4 ++-- .../d/deprecated/deprecated_module_py39_earlier_pyversion.txt | 1 - 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/functional/d/deprecated/deprecated_module_py39.py b/tests/functional/d/deprecated/deprecated_module_py39.py index 8f1ef8c5e0..8f5827cefc 100644 --- a/tests/functional/d/deprecated/deprecated_module_py39.py +++ b/tests/functional/d/deprecated/deprecated_module_py39.py @@ -1,4 +1,4 @@ """Test deprecated modules from Python 3.9.""" -# pylint: disable=unused-import +# pylint: disable=unused-import, import-error -import binhex # [deprecated-module, import-error] +import binhex # [deprecated-module] diff --git a/tests/functional/d/deprecated/deprecated_module_py39.txt b/tests/functional/d/deprecated/deprecated_module_py39.txt index c584213291..b3ee13c050 100644 --- a/tests/functional/d/deprecated/deprecated_module_py39.txt +++ b/tests/functional/d/deprecated/deprecated_module_py39.txt @@ -1,2 +1 @@ deprecated-module:4:0:4:13::Deprecated module 'binhex':UNDEFINED -import-error:4:0:4:13::Unable to import 'binhex':UNDEFINED diff --git a/tests/functional/d/deprecated/deprecated_module_py39_earlier_pyversion.py b/tests/functional/d/deprecated/deprecated_module_py39_earlier_pyversion.py index 4b15907cf4..dc3d83558d 100644 --- a/tests/functional/d/deprecated/deprecated_module_py39_earlier_pyversion.py +++ b/tests/functional/d/deprecated/deprecated_module_py39_earlier_pyversion.py @@ -1,6 +1,6 @@ """Test deprecated modules from Python 3.9, but use an earlier --py-version and ensure a warning is still emitted. """ -# pylint: disable=unused-import +# pylint: disable=unused-import, import-error -import binhex # [deprecated-module, import-error] +import binhex # [deprecated-module] diff --git a/tests/functional/d/deprecated/deprecated_module_py39_earlier_pyversion.txt b/tests/functional/d/deprecated/deprecated_module_py39_earlier_pyversion.txt index d079403287..3ddb6b21d0 100644 --- a/tests/functional/d/deprecated/deprecated_module_py39_earlier_pyversion.txt +++ b/tests/functional/d/deprecated/deprecated_module_py39_earlier_pyversion.txt @@ -1,2 +1 @@ deprecated-module:6:0:6:13::Deprecated module 'binhex':UNDEFINED -import-error:6:0:6:13::Unable to import 'binhex':UNDEFINED