From aeffe5229de78ab88d2daf20f8e3937822737d7e Mon Sep 17 00:00:00 2001 From: "pylint-backport[bot]" <212256041+pylint-backport[bot]@users.noreply.github.com> Date: Sun, 26 Oct 2025 06:32:11 +0000 Subject: [PATCH 01/10] [Backport maintenance/4.0.x] Fix FP for `invalid-name` with `typing.Annotated` (#10701) Fix FP for `invalid-name` with `typing.Annotated` (#10699) (cherry picked from commit bb9df1639192eb9de2a9ce72eaa70bfb9c19f3b5) Co-authored-by: Jacob Walls --- doc/whatsnew/fragments/10696.false_positive | 3 ++ pylint/checkers/base/name_checker/checker.py | 34 +++++++++++++------ .../invalid_name/invalid_name_module_level.py | 4 +++ 3 files changed, 30 insertions(+), 11 deletions(-) create mode 100644 doc/whatsnew/fragments/10696.false_positive diff --git a/doc/whatsnew/fragments/10696.false_positive b/doc/whatsnew/fragments/10696.false_positive new file mode 100644 index 0000000000..9a341efe24 --- /dev/null +++ b/doc/whatsnew/fragments/10696.false_positive @@ -0,0 +1,3 @@ +Fixed false positive for ``invalid-name`` with ``typing.Annotated``. + +Closes #10696 diff --git a/pylint/checkers/base/name_checker/checker.py b/pylint/checkers/base/name_checker/checker.py index 3cb1c336da..d282ab5eda 100644 --- a/pylint/checkers/base/name_checker/checker.py +++ b/pylint/checkers/base/name_checker/checker.py @@ -488,17 +488,7 @@ def visit_assignname( # pylint: disable=too-many-branches,too-many-statements return # Check classes (TypeVar's are classes so they need to be excluded first) - elif isinstance(inferred_assign_type, nodes.ClassDef) or ( - isinstance(inferred_assign_type, bases.Instance) - and {"EnumMeta", "TypedDict"}.intersection( - { - ancestor.name - for ancestor in cast( - InferenceResult, inferred_assign_type - ).mro() - } - ) - ): + elif self._should_check_class_regex(inferred_assign_type): self._check_name("class", node.name, node) # Don't emit if the name redefines an import in an ImportError except handler @@ -576,6 +566,28 @@ def _meets_exception_for_non_consts( regexp = self._name_regexps["variable"] return regexp.match(name) is not None + def _should_check_class_regex( + self, inferred_assign_type: InferenceResult | None + ) -> bool: + if isinstance(inferred_assign_type, nodes.ClassDef): + return True + if isinstance(inferred_assign_type, bases.Instance) and { + "EnumMeta", + "TypedDict", + }.intersection( + { + ancestor.name + for ancestor in cast(InferenceResult, inferred_assign_type).mro() + } + ): + return True + if ( + isinstance(inferred_assign_type, nodes.FunctionDef) + and inferred_assign_type.qname() == "typing.Annotated" + ): + return True + return False + def _recursive_check_names(self, args: list[nodes.AssignName]) -> None: """Check names in a possibly recursive list .""" for arg in args: diff --git a/tests/functional/i/invalid/invalid_name/invalid_name_module_level.py b/tests/functional/i/invalid/invalid_name/invalid_name_module_level.py index 9eae16b7c1..99323d1119 100644 --- a/tests/functional/i/invalid/invalid_name/invalid_name_module_level.py +++ b/tests/functional/i/invalid/invalid_name/invalid_name_module_level.py @@ -51,3 +51,7 @@ def A(): # [invalid-name] VERSION = version("ty") # uninferable except PackageNotFoundError: VERSION = "0.0.0" + + +from typing import Annotated +IntWithAnnotation = Annotated[int, "anything"] From fc920b63cec815c94fa1c9713bf3529213ea780c Mon Sep 17 00:00:00 2001 From: "pylint-backport[bot]" <212256041+pylint-backport[bot]@users.noreply.github.com> Date: Mon, 3 Nov 2025 12:46:45 +0000 Subject: [PATCH 02/10] [Backport maintenance/4.0.x] Fix false positive for `f-string-without-interpolation` with template strings when using format spec (#10717) Fix false positive for `f-string-without-interpolation` with template strings when using format spec (#10716) (cherry picked from commit d2589f127721e29cb4d6fc0178019be3ba2485a9) Co-authored-by: Zen Lee <53538590+zenlyj@users.noreply.github.com> --- doc/whatsnew/fragments/10702.false_positive | 4 ++++ pylint/checkers/strings.py | 2 +- tests/functional/f/f_string_without_interpolation_py314.py | 4 ++++ tests/functional/f/f_string_without_interpolation_py314.rc | 2 ++ 4 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 doc/whatsnew/fragments/10702.false_positive create mode 100644 tests/functional/f/f_string_without_interpolation_py314.py create mode 100644 tests/functional/f/f_string_without_interpolation_py314.rc diff --git a/doc/whatsnew/fragments/10702.false_positive b/doc/whatsnew/fragments/10702.false_positive new file mode 100644 index 0000000000..301d691fae --- /dev/null +++ b/doc/whatsnew/fragments/10702.false_positive @@ -0,0 +1,4 @@ +Fix false positive for ``f-string-without-interpolation`` with template strings +when using format spec. + +Closes #10702 diff --git a/pylint/checkers/strings.py b/pylint/checkers/strings.py index 0260798b46..644974b741 100644 --- a/pylint/checkers/strings.py +++ b/pylint/checkers/strings.py @@ -409,7 +409,7 @@ def visit_joinedstr(self, node: nodes.JoinedStr) -> None: self._check_interpolation(node) def _check_interpolation(self, node: nodes.JoinedStr) -> None: - if isinstance(node.parent, nodes.FormattedValue): + if isinstance(node.parent, (nodes.TemplateStr, nodes.FormattedValue)): return for value in node.values: if isinstance(value, nodes.FormattedValue): diff --git a/tests/functional/f/f_string_without_interpolation_py314.py b/tests/functional/f/f_string_without_interpolation_py314.py new file mode 100644 index 0000000000..7aa00a824d --- /dev/null +++ b/tests/functional/f/f_string_without_interpolation_py314.py @@ -0,0 +1,4 @@ +# pylint: disable=missing-module-docstring + +PI = 3.14 +print(t"{PI:.1f}") diff --git a/tests/functional/f/f_string_without_interpolation_py314.rc b/tests/functional/f/f_string_without_interpolation_py314.rc new file mode 100644 index 0000000000..a4a5d4fab5 --- /dev/null +++ b/tests/functional/f/f_string_without_interpolation_py314.rc @@ -0,0 +1,2 @@ +[testoptions] +min_pyver=3.14 From 1a26dea39c621993eb045459ad1a4a5ec48412ed Mon Sep 17 00:00:00 2001 From: "pylint-backport[bot]" <212256041+pylint-backport[bot]@users.noreply.github.com> Date: Sat, 8 Nov 2025 08:26:14 +0000 Subject: [PATCH 03/10] [Backport maintenance/4.0.x] Add Enum dunder to the list of allowed dunder (#10725) Add Enum dunder to the list of allowed dunder (#10722) (cherry picked from commit 0426f8b8efec21ee167c53b40dc5d22b9729d31b) Co-authored-by: Trinh Quoc Anh Co-authored-by: Pierre Sassoulas Co-authored-by: Mark Byrne <31762852+mbyrnepr2@users.noreply.github.com> --- doc/whatsnew/fragments/10435.false_positive | 3 ++ pylint/constants.py | 45 ++++++++++++--------- pylint/extensions/dunder.py | 9 ++--- 3 files changed, 32 insertions(+), 25 deletions(-) create mode 100644 doc/whatsnew/fragments/10435.false_positive diff --git a/doc/whatsnew/fragments/10435.false_positive b/doc/whatsnew/fragments/10435.false_positive new file mode 100644 index 0000000000..0ad1a29cb0 --- /dev/null +++ b/doc/whatsnew/fragments/10435.false_positive @@ -0,0 +1,3 @@ +Add Enum dunder methods ``_generate_next_value_``, ``_missing_``, ``_numeric_repr_``, ``_add_alias_``, and ``_add_value_alias_`` to the list passed to ``--good-dunder-names``. + +Closes #10435 diff --git a/pylint/constants.py b/pylint/constants.py index c48fe7af0e..6a2481913b 100644 --- a/pylint/constants.py +++ b/pylint/constants.py @@ -219,26 +219,31 @@ def _get_pylint_home() -> str: "__anext__": "Use anext built-in function", }, } - -EXTRA_DUNDER_METHODS = [ - "__new__", - "__subclasses__", - "__init_subclass__", - "__set_name__", - "__class_getitem__", - "__missing__", - "__exit__", - "__await__", - "__aexit__", - "__getnewargs_ex__", - "__getnewargs__", - "__getstate__", - "__index__", - "__setstate__", - "__reduce__", - "__reduce_ex__", - "__post_init__", # part of `dataclasses` module -] +EXTRA_DUNDER_METHODS: dict[tuple[int, int], list[str]] = { + (0, 0): [ + "__new__", + "__subclasses__", + "__init_subclass__", + "__set_name__", + "__class_getitem__", + "__missing__", + "__exit__", + "__await__", + "__aexit__", + "__getnewargs_ex__", + "__getnewargs__", + "__getstate__", + "__index__", + "__setstate__", + "__reduce__", + "__reduce_ex__", + "__post_init__", # part of `dataclasses` module + "_generate_next_value_", + "_missing_", + "_numeric_repr_", + ], + (3, 13): ["_add_alias_", "_add_value_alias_"], +} DUNDER_PROPERTIES = [ "__class__", diff --git a/pylint/extensions/dunder.py b/pylint/extensions/dunder.py index 1683f81476..4d0fd65d65 100644 --- a/pylint/extensions/dunder.py +++ b/pylint/extensions/dunder.py @@ -41,11 +41,10 @@ class DunderChecker(BaseChecker): ) def open(self) -> None: - self._dunder_methods = ( - EXTRA_DUNDER_METHODS - + DUNDER_PROPERTIES - + self.linter.config.good_dunder_names - ) + self._dunder_methods = DUNDER_PROPERTIES + self.linter.config.good_dunder_names + for since_vers, extra_dunder_methods in EXTRA_DUNDER_METHODS.items(): + if since_vers <= self.linter.config.py_version: + self._dunder_methods.extend(extra_dunder_methods) for since_vers, dunder_methods in DUNDER_METHODS.items(): if since_vers <= self.linter.config.py_version: self._dunder_methods.extend(list(dunder_methods.keys())) From b128b7d909bf541b2978d84bfe5ed4f4d67210e5 Mon Sep 17 00:00:00 2001 From: "pylint-backport[bot]" <212256041+pylint-backport[bot]@users.noreply.github.com> Date: Sun, 9 Nov 2025 19:26:12 +0000 Subject: [PATCH 04/10] [Backport maintenance/4.0.x] Fix a false positive for ``unbalanced-tuple-unpacking``. (#10726) Fix a false positive for ``unbalanced-tuple-unpacking``. (#10724) * Fix a false positive for ``unbalanced-tuple-unpacking`` when a tuple is assigned to a function call and the structure of the function's return value is ambiguous. Closes #10721 (cherry picked from commit 14963400ced46c4e69f46e0aabcf9bd6fe83b90f) Co-authored-by: Mark Byrne <31762852+mbyrnepr2@users.noreply.github.com> Co-authored-by: Pierre Sassoulas --- doc/whatsnew/fragments/10721.false_positive | 3 +++ pylint/checkers/variables.py | 7 +++---- .../u/unbalanced/unbalanced_tuple_unpacking.py | 11 +++++++++++ 3 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 doc/whatsnew/fragments/10721.false_positive diff --git a/doc/whatsnew/fragments/10721.false_positive b/doc/whatsnew/fragments/10721.false_positive new file mode 100644 index 0000000000..cb4fa3d485 --- /dev/null +++ b/doc/whatsnew/fragments/10721.false_positive @@ -0,0 +1,3 @@ +Fix a false positive for ``unbalanced-tuple-unpacking`` when a tuple is assigned to a function call and the structure of the function's return value is ambiguous. + +Closes #10721 diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py index 43fb86fe34..5add0732c0 100644 --- a/pylint/checkers/variables.py +++ b/pylint/checkers/variables.py @@ -2162,11 +2162,10 @@ def visit_assign(self, node: nodes.Assign) -> None: # Check if we have starred nodes. if any(isinstance(target, nodes.Starred) for target in targets): return - try: - inferred = utils.safe_infer(node.value) - if inferred is not None: - self._check_unpacking(inferred, node, targets) + inferred = node.value.inferred() + if inferred is not None and len(inferred) == 1: + self._check_unpacking(inferred[0], node, targets) except astroid.InferenceError: return diff --git a/tests/functional/u/unbalanced/unbalanced_tuple_unpacking.py b/tests/functional/u/unbalanced/unbalanced_tuple_unpacking.py index d6c315e9e9..308715afaf 100644 --- a/tests/functional/u/unbalanced/unbalanced_tuple_unpacking.py +++ b/tests/functional/u/unbalanced/unbalanced_tuple_unpacking.py @@ -167,3 +167,14 @@ def my_function(mystring): # Using a lot of args, so we have a high probability to still trigger the problem if # we add arguments to our unittest command later (p, q, r, s, t, u, v, w, x, y, z) = sys.argv # pylint: disable=invalid-name + + +# https://github.com/pylint-dev/pylint/issues/10721 +def fruit(apple: int, pear: int, kiwi: int | None = None) -> tuple[int, int] | tuple[int, int, int]: + return (apple, pear) if kiwi is None else (apple, pear, kiwi) + +def main(): + _, _ = fruit(1, 2) + _, _ = fruit(1, 2, 3) # known false negative, requires better None comprehension in astroid + _, _, _ = fruit(1, 2) # known false negative, requires better None comprehension in astroid + _, _, _ = fruit(1, 2, 3) From 0ed81725382db48ac0061c96c1948f42fe75f85d Mon Sep 17 00:00:00 2001 From: "pylint-backport[bot]" <212256041+pylint-backport[bot]@users.noreply.github.com> Date: Sun, 9 Nov 2025 19:47:02 +0000 Subject: [PATCH 05/10] [Backport maintenance/4.0.x] Fix crash when a `slice` object is called (#10728) Fix crash when a `slice` object is called (#10715) (cherry picked from commit 0a2cb3391e6562e17535c3cdbbb19b98f595f01e) Co-authored-by: Zen Lee <53538590+zenlyj@users.noreply.github.com> Co-authored-by: Pierre Sassoulas --- doc/whatsnew/fragments/10708.bugfix | 4 ++++ pylint/extensions/code_style.py | 2 +- .../functional/ext/code_style/cs_prefer_typing_namedtuple.py | 5 +++++ 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 doc/whatsnew/fragments/10708.bugfix diff --git a/doc/whatsnew/fragments/10708.bugfix b/doc/whatsnew/fragments/10708.bugfix new file mode 100644 index 0000000000..2a9b1a3793 --- /dev/null +++ b/doc/whatsnew/fragments/10708.bugfix @@ -0,0 +1,4 @@ +Fix crash for ``prefer-typing-namedtuple`` and ``consider-math-not-float`` when +a ``slice`` object is called. + +Closes #10708 diff --git a/pylint/extensions/code_style.py b/pylint/extensions/code_style.py index d8ea869cb9..0eff5f4786 100644 --- a/pylint/extensions/code_style.py +++ b/pylint/extensions/code_style.py @@ -113,7 +113,7 @@ def open(self) -> None: def visit_call(self, node: nodes.Call) -> None: if self._py36_plus: called = safe_infer(node.func) - if not called: + if not (called and isinstance(called, (nodes.FunctionDef, nodes.ClassDef))): return if called.qname() == "collections.namedtuple": self.add_message( diff --git a/tests/functional/ext/code_style/cs_prefer_typing_namedtuple.py b/tests/functional/ext/code_style/cs_prefer_typing_namedtuple.py index 7b0e7c58de..18ca3138f8 100644 --- a/tests/functional/ext/code_style/cs_prefer_typing_namedtuple.py +++ b/tests/functional/ext/code_style/cs_prefer_typing_namedtuple.py @@ -7,3 +7,8 @@ class SearchMatch( namedtuple('SearchMatch', ['els', 'index', 'iterator']) # [prefer-typing-namedtuple] ): """Adapted from primer package `music21`.""" + + +# Regression test for https://github.com/pylint-dev/pylint/issues/10708 +x = slice(42) +x() # pylint: disable=not-callable From 108191ebbcd9dc8fa9e3fb71c83fd247d2f6ccd1 Mon Sep 17 00:00:00 2001 From: "pylint-backport[bot]" <212256041+pylint-backport[bot]@users.noreply.github.com> Date: Sun, 9 Nov 2025 20:35:45 +0000 Subject: [PATCH 06/10] [Backport maintenance/4.0.x] Fix a false positive for class attribute typed with Final (#10727) Fix a false positive for class attribute typed with Final (#10712) (cherry picked from commit 133681e8741d2bb80d0d6e5eb18cd2725e6fe70b) Co-authored-by: Pierre Sassoulas Co-authored-by: Jacob Walls --- doc/whatsnew/fragments/10711.false_positive | 4 +++ pylint/checkers/base/name_checker/checker.py | 4 ++- .../invalid_name_with_final_typing.py | 26 +++++++++++++++++++ .../invalid_name_with_final_typing.txt | 4 +++ 4 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 doc/whatsnew/fragments/10711.false_positive create mode 100644 tests/functional/i/invalid/invalid_name/invalid_name_with_final_typing.py create mode 100644 tests/functional/i/invalid/invalid_name/invalid_name_with_final_typing.txt diff --git a/doc/whatsnew/fragments/10711.false_positive b/doc/whatsnew/fragments/10711.false_positive new file mode 100644 index 0000000000..af4b822638 --- /dev/null +++ b/doc/whatsnew/fragments/10711.false_positive @@ -0,0 +1,4 @@ +Fix a false positive when an UPPER_CASED class attribute was raising an +``invalid-name`` when typed with ``Final``. + +Closes #10711 diff --git a/pylint/checkers/base/name_checker/checker.py b/pylint/checkers/base/name_checker/checker.py index d282ab5eda..4530e78822 100644 --- a/pylint/checkers/base/name_checker/checker.py +++ b/pylint/checkers/base/name_checker/checker.py @@ -373,7 +373,9 @@ def leave_module(self, _: nodes.Module) -> None: def visit_classdef(self, node: nodes.ClassDef) -> None: self._check_name("class", node.name, node) for attr, anodes in node.instance_attrs.items(): - if not any(node.instance_attr_ancestors(attr)): + if not any( + node.instance_attr_ancestors(attr) + ) and not utils.is_assign_name_annotated_with(anodes[0], "Final"): self._check_name("attr", attr, anodes[0]) @utils.only_required_for_messages("disallowed-name", "invalid-name") diff --git a/tests/functional/i/invalid/invalid_name/invalid_name_with_final_typing.py b/tests/functional/i/invalid/invalid_name/invalid_name_with_final_typing.py new file mode 100644 index 0000000000..3d32d8a2b4 --- /dev/null +++ b/tests/functional/i/invalid/invalid_name/invalid_name_with_final_typing.py @@ -0,0 +1,26 @@ +"""Regression test for https://github.com/pylint-dev/pylint/issues/10711.""" + +# pylint: disable=missing-class-docstring, missing-function-docstring + +from dataclasses import dataclass +from typing import Final + +module_snake_case_constant: Final[int] = 42 # [invalid-name] +MODULE_UPPER_CASE_CONSTANT: Final[int] = 42 + + +def function() -> None: + function_snake_case_constant: Final[int] = 42 + FUNCTION_UPPER_CASE_CONSTANT: Final[int] = 42 # [invalid-name] + print(function_snake_case_constant, FUNCTION_UPPER_CASE_CONSTANT) + + +@dataclass +class Class: + class_snake_case_constant: Final[int] = 42 # [invalid-name] + CLASS_UPPER_CASE_CONSTANT: Final[int] = 42 + + def method(self) -> None: + method_snake_case_constant: Final[int] = 42 + METHOD_UPPER_CASE_CONSTANT: Final[int] = 42 # [invalid-name] + print(method_snake_case_constant, METHOD_UPPER_CASE_CONSTANT) diff --git a/tests/functional/i/invalid/invalid_name/invalid_name_with_final_typing.txt b/tests/functional/i/invalid/invalid_name/invalid_name_with_final_typing.txt new file mode 100644 index 0000000000..595b35224c --- /dev/null +++ b/tests/functional/i/invalid/invalid_name/invalid_name_with_final_typing.txt @@ -0,0 +1,4 @@ +invalid-name:8:0:8:26::"Constant name ""module_snake_case_constant"" doesn't conform to UPPER_CASE naming style":HIGH +invalid-name:14:4:14:32:function:"Variable name ""FUNCTION_UPPER_CASE_CONSTANT"" doesn't conform to snake_case naming style":HIGH +invalid-name:20:4:20:29:Class:"Class constant name ""class_snake_case_constant"" doesn't conform to UPPER_CASE naming style":HIGH +invalid-name:25:8:25:34:Class.method:"Variable name ""METHOD_UPPER_CASE_CONSTANT"" doesn't conform to snake_case naming style":HIGH From c96a9e4d232abcfa1d7f449839b68337816305e9 Mon Sep 17 00:00:00 2001 From: "pylint-backport[bot]" <212256041+pylint-backport[bot]@users.noreply.github.com> Date: Sun, 9 Nov 2025 21:40:13 +0100 Subject: [PATCH 07/10] [Backport maintenance/4.0.x] Fix crash when a variable annotation is used as `if` test expression (#10729) Fix crash when a variable annotation is used as `if` test expression (#10714) Fix crash for ``consider-using-assignment-expr``. (cherry picked from commit 926529bb3288402c7ccc96a9f5bd7ca85cf38390) Co-authored-by: Zen Lee <53538590+zenlyj@users.noreply.github.com> --- doc/whatsnew/fragments/10707.bugfix | 4 ++++ pylint/extensions/code_style.py | 2 +- .../ext/code_style/cs_consider_using_assignment_expr.py | 5 +++++ 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 doc/whatsnew/fragments/10707.bugfix diff --git a/doc/whatsnew/fragments/10707.bugfix b/doc/whatsnew/fragments/10707.bugfix new file mode 100644 index 0000000000..cd82216b74 --- /dev/null +++ b/doc/whatsnew/fragments/10707.bugfix @@ -0,0 +1,4 @@ +Fix crash for ``consider-using-assignment-expr`` when a variable annotation without assignment +is used as the ``if`` test expression. + +Closes #10707 diff --git a/pylint/extensions/code_style.py b/pylint/extensions/code_style.py index 0eff5f4786..8d045a40ca 100644 --- a/pylint/extensions/code_style.py +++ b/pylint/extensions/code_style.py @@ -314,7 +314,7 @@ def _check_prev_sibling_to_if_stmt( case nodes.Assign( targets=[nodes.AssignName(name=target_name)] ) | nodes.AnnAssign(target=nodes.AssignName(name=target_name)): - return target_name == name # type: ignore[no-any-return] + return target_name == name and prev_sibling.value is not None return False @staticmethod diff --git a/tests/functional/ext/code_style/cs_consider_using_assignment_expr.py b/tests/functional/ext/code_style/cs_consider_using_assignment_expr.py index 62f5ba7a9b..aba15bd2e4 100644 --- a/tests/functional/ext/code_style/cs_consider_using_assignment_expr.py +++ b/tests/functional/ext/code_style/cs_consider_using_assignment_expr.py @@ -157,3 +157,8 @@ class A: A.var = 2 if A.var: ... + + +i: int +if i: # pylint: disable=used-before-assignment + pass From 755f2d0327809a5b358b99ad7fc67a7a5a2faad0 Mon Sep 17 00:00:00 2001 From: "pylint-backport[bot]" <212256041+pylint-backport[bot]@users.noreply.github.com> Date: Mon, 10 Nov 2025 15:57:26 +0100 Subject: [PATCH 08/10] [Backport maintenance/4.0.x] Upgrade astroid to 4.0.2 (#10733) Upgrade astroid to 4.0.2 (#10730) Closes #10624 (cherry picked from commit 361a2b82ca6d187a6ba49f95f27d22d23f0ca39c) Co-authored-by: Pierre Sassoulas --- pyproject.toml | 2 +- requirements_test_min.txt | 2 +- .../unused_name_in_string_literal_type_annotation_py38.py | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c5b8c7eec2..49c08d428c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,7 +40,7 @@ dependencies = [ # Also upgrade requirements_test_min.txt. # Pinned to dev of second minor update to allow editable installs and fix primer issues, # see https://github.com/pylint-dev/astroid/issues/1341 - "astroid>=4.0.1,<=4.1.dev0", + "astroid>=4.0.2,<=4.1.dev0", "colorama>=0.4.5; sys_platform=='win32'", "dill>=0.2; python_version<'3.11'", "dill>=0.3.6; python_version>='3.11'", diff --git a/requirements_test_min.txt b/requirements_test_min.txt index 5966b31576..29e05b3c94 100644 --- a/requirements_test_min.txt +++ b/requirements_test_min.txt @@ -1,6 +1,6 @@ .[testutils,spelling] # astroid dependency is also defined in pyproject.toml -astroid==4.0.1 # Pinned to a specific version for tests +astroid==4.0.2 # Pinned to a specific version for tests typing-extensions~=4.15 py~=1.11.0 pytest~=8.4 diff --git a/tests/functional/u/unused/unused_name_in_string_literal_type_annotation_py38.py b/tests/functional/u/unused/unused_name_in_string_literal_type_annotation_py38.py index d8eb811697..14aaf61532 100644 --- a/tests/functional/u/unused/unused_name_in_string_literal_type_annotation_py38.py +++ b/tests/functional/u/unused/unused_name_in_string_literal_type_annotation_py38.py @@ -3,7 +3,7 @@ from argparse import ArgumentParser # [unused-import] from argparse import Namespace # [unused-import] import http # [unused-import] -from http import HTTPStatus +from http import HTTPStatus, HTTPMethod import typing as t from typing import Literal as Lit @@ -25,3 +25,6 @@ def unused_variable_example(): # See https://peps.python.org/pep-0586/#literals-enums-and-forward-references example4: t.Literal["http.HTTPStatus.OK", "http.HTTPStatus.NOT_FOUND"] example5: "t.Literal[HTTPStatus.OK, HTTPStatus.NOT_FOUND]" + +# Regression test for https://github.com/pylint-dev/pylint/issues/10624 +print(HTTPMethod.CONNECT) From 77b0cd8c0e40eb563ab96067be6bdb3e9e266f1e Mon Sep 17 00:00:00 2001 From: "pylint-backport[bot]" <212256041+pylint-backport[bot]@users.noreply.github.com> Date: Thu, 13 Nov 2025 08:26:58 +0000 Subject: [PATCH 09/10] [Backport maintenance/4.0.x] fix(expand_modules): pass ignore_list to modutils.get_module_files (#10740) fix(expand_modules): pass ignore_list to modutils.get_module_files (#10720) (cherry picked from commit cd2839daf0a5516c0a79b0db7e170a8f0f8661a0) Co-authored-by: shifqu --- doc/whatsnew/fragments/10669.bugfix | 3 +++ pylint/lint/expand_modules.py | 2 +- tests/lint/unittest_expand_modules.py | 20 +++++++++++++++++++ .../ignore_option_10669/__init__.py | 0 .../regrtest_data/ignore_option_10669/main.py | 3 +++ .../ignore_option_10669/test/__init__.py | 4 ++++ 6 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 doc/whatsnew/fragments/10669.bugfix create mode 100644 tests/regrtest_data/ignore_option_10669/__init__.py create mode 100644 tests/regrtest_data/ignore_option_10669/main.py create mode 100644 tests/regrtest_data/ignore_option_10669/test/__init__.py diff --git a/doc/whatsnew/fragments/10669.bugfix b/doc/whatsnew/fragments/10669.bugfix new file mode 100644 index 0000000000..035d3389d8 --- /dev/null +++ b/doc/whatsnew/fragments/10669.bugfix @@ -0,0 +1,3 @@ +Make 'ignore' option work as expected again. + +Closes #10669 diff --git a/pylint/lint/expand_modules.py b/pylint/lint/expand_modules.py index 0116c9bb7a..d51af24f60 100644 --- a/pylint/lint/expand_modules.py +++ b/pylint/lint/expand_modules.py @@ -150,7 +150,7 @@ def expand_modules( ) if has_init or is_namespace or is_directory: for subfilepath in modutils.get_module_files( - os.path.dirname(filepath) or ".", [], list_all=is_namespace + os.path.dirname(filepath) or ".", ignore_list, list_all=is_namespace ): subfilepath = os.path.normpath(subfilepath) if filepath == subfilepath: diff --git a/tests/lint/unittest_expand_modules.py b/tests/lint/unittest_expand_modules.py index 054687d0ab..5b3a7ddbbe 100644 --- a/tests/lint/unittest_expand_modules.py +++ b/tests/lint/unittest_expand_modules.py @@ -326,3 +326,23 @@ def test_expand_modules_with_ignore( ) assert {k: v for k, v in modules.items() if not v["isignored"]} == expected assert not errors + + @set_config(ignore=["test"]) + def test_expand_modules_with_ignore_list(self) -> None: + """Test expand_modules with a non-default value of ignore.""" + ignore_list: list[str] = self.linter.config.ignore + ignore_list_re = [re.compile("^\\.#")] + path = Path(__file__).parent.parent / "regrtest_data" / "ignore_option_10669" + modules, errors = expand_modules( + [str(path)], + [], + ignore_list, + ignore_list_re, + [], + ) + expected_keys = { + str(path / "__init__.py"), + str(path / "main.py"), + } + assert {k for k, v in modules.items() if not v["isignored"]} == expected_keys + assert not errors diff --git a/tests/regrtest_data/ignore_option_10669/__init__.py b/tests/regrtest_data/ignore_option_10669/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/regrtest_data/ignore_option_10669/main.py b/tests/regrtest_data/ignore_option_10669/main.py new file mode 100644 index 0000000000..a83ef2e8af --- /dev/null +++ b/tests/regrtest_data/ignore_option_10669/main.py @@ -0,0 +1,3 @@ +# pylint: disable=too-few-public-methods,missing-docstring +class A: + pass diff --git a/tests/regrtest_data/ignore_option_10669/test/__init__.py b/tests/regrtest_data/ignore_option_10669/test/__init__.py new file mode 100644 index 0000000000..268eb0f2d8 --- /dev/null +++ b/tests/regrtest_data/ignore_option_10669/test/__init__.py @@ -0,0 +1,4 @@ + +class i: + """many issues here""" + pass From 84b6552b86e210097ac29de7ef64b152efb4a454 Mon Sep 17 00:00:00 2001 From: Pierre Sassoulas Date: Thu, 13 Nov 2025 15:56:42 +0100 Subject: [PATCH 10/10] Bump pylint to 4.0.3, update changelog (#10741) --- doc/whatsnew/4/4.0/index.rst | 51 +++++++++++++++++++++ doc/whatsnew/fragments/10435.false_positive | 3 -- doc/whatsnew/fragments/10669.bugfix | 3 -- doc/whatsnew/fragments/10696.false_positive | 3 -- doc/whatsnew/fragments/10702.false_positive | 4 -- doc/whatsnew/fragments/10707.bugfix | 4 -- doc/whatsnew/fragments/10708.bugfix | 4 -- doc/whatsnew/fragments/10711.false_positive | 4 -- doc/whatsnew/fragments/10721.false_positive | 3 -- pylint/__pkginfo__.py | 2 +- tbump.toml | 2 +- 11 files changed, 53 insertions(+), 30 deletions(-) delete mode 100644 doc/whatsnew/fragments/10435.false_positive delete mode 100644 doc/whatsnew/fragments/10669.bugfix delete mode 100644 doc/whatsnew/fragments/10696.false_positive delete mode 100644 doc/whatsnew/fragments/10702.false_positive delete mode 100644 doc/whatsnew/fragments/10707.bugfix delete mode 100644 doc/whatsnew/fragments/10708.bugfix delete mode 100644 doc/whatsnew/fragments/10711.false_positive delete mode 100644 doc/whatsnew/fragments/10721.false_positive diff --git a/doc/whatsnew/4/4.0/index.rst b/doc/whatsnew/4/4.0/index.rst index 4d7c20b612..78d5847021 100644 --- a/doc/whatsnew/4/4.0/index.rst +++ b/doc/whatsnew/4/4.0/index.rst @@ -74,6 +74,57 @@ to your liking. .. towncrier release notes start +What's new in Pylint 4.0.3? +--------------------------- +Release date: 2025-11-13 + + +False Positives Fixed +--------------------- + +- Add Enum dunder methods ``_generate_next_value_``, ``_missing_``, ``_numeric_repr_``, ``_add_alias_``, and ``_add_value_alias_`` to the list passed to ``--good-dunder-names``. + + Closes #10435 (`#10435 `_) + +- Fixed false positive for ``invalid-name`` with ``typing.Annotated``. + + Closes #10696 (`#10696 `_) + +- Fix false positive for ``f-string-without-interpolation`` with template strings + when using format spec. + + Closes #10702 (`#10702 `_) + +- Fix a false positive when an UPPER_CASED class attribute was raising an + ``invalid-name`` when typed with ``Final``. + + Closes #10711 (`#10711 `_) + +- Fix a false positive for ``unbalanced-tuple-unpacking`` when a tuple is assigned to a function call and the structure of the function's return value is ambiguous. + + Closes #10721 (`#10721 `_) + + + +Other Bug Fixes +--------------- + +- Make 'ignore' option work as expected again. + + Closes #10669 (`#10669 `_) + +- Fix crash for ``consider-using-assignment-expr`` when a variable annotation without assignment + is used as the ``if`` test expression. + + Closes #10707 (`#10707 `_) + +- Fix crash for ``prefer-typing-namedtuple`` and ``consider-math-not-float`` when + a ``slice`` object is called. + + Closes #10708 (`#10708 `_) + + + What's new in Pylint 4.0.2? -------------------------------- Release date: 2025-10-20 diff --git a/doc/whatsnew/fragments/10435.false_positive b/doc/whatsnew/fragments/10435.false_positive deleted file mode 100644 index 0ad1a29cb0..0000000000 --- a/doc/whatsnew/fragments/10435.false_positive +++ /dev/null @@ -1,3 +0,0 @@ -Add Enum dunder methods ``_generate_next_value_``, ``_missing_``, ``_numeric_repr_``, ``_add_alias_``, and ``_add_value_alias_`` to the list passed to ``--good-dunder-names``. - -Closes #10435 diff --git a/doc/whatsnew/fragments/10669.bugfix b/doc/whatsnew/fragments/10669.bugfix deleted file mode 100644 index 035d3389d8..0000000000 --- a/doc/whatsnew/fragments/10669.bugfix +++ /dev/null @@ -1,3 +0,0 @@ -Make 'ignore' option work as expected again. - -Closes #10669 diff --git a/doc/whatsnew/fragments/10696.false_positive b/doc/whatsnew/fragments/10696.false_positive deleted file mode 100644 index 9a341efe24..0000000000 --- a/doc/whatsnew/fragments/10696.false_positive +++ /dev/null @@ -1,3 +0,0 @@ -Fixed false positive for ``invalid-name`` with ``typing.Annotated``. - -Closes #10696 diff --git a/doc/whatsnew/fragments/10702.false_positive b/doc/whatsnew/fragments/10702.false_positive deleted file mode 100644 index 301d691fae..0000000000 --- a/doc/whatsnew/fragments/10702.false_positive +++ /dev/null @@ -1,4 +0,0 @@ -Fix false positive for ``f-string-without-interpolation`` with template strings -when using format spec. - -Closes #10702 diff --git a/doc/whatsnew/fragments/10707.bugfix b/doc/whatsnew/fragments/10707.bugfix deleted file mode 100644 index cd82216b74..0000000000 --- a/doc/whatsnew/fragments/10707.bugfix +++ /dev/null @@ -1,4 +0,0 @@ -Fix crash for ``consider-using-assignment-expr`` when a variable annotation without assignment -is used as the ``if`` test expression. - -Closes #10707 diff --git a/doc/whatsnew/fragments/10708.bugfix b/doc/whatsnew/fragments/10708.bugfix deleted file mode 100644 index 2a9b1a3793..0000000000 --- a/doc/whatsnew/fragments/10708.bugfix +++ /dev/null @@ -1,4 +0,0 @@ -Fix crash for ``prefer-typing-namedtuple`` and ``consider-math-not-float`` when -a ``slice`` object is called. - -Closes #10708 diff --git a/doc/whatsnew/fragments/10711.false_positive b/doc/whatsnew/fragments/10711.false_positive deleted file mode 100644 index af4b822638..0000000000 --- a/doc/whatsnew/fragments/10711.false_positive +++ /dev/null @@ -1,4 +0,0 @@ -Fix a false positive when an UPPER_CASED class attribute was raising an -``invalid-name`` when typed with ``Final``. - -Closes #10711 diff --git a/doc/whatsnew/fragments/10721.false_positive b/doc/whatsnew/fragments/10721.false_positive deleted file mode 100644 index cb4fa3d485..0000000000 --- a/doc/whatsnew/fragments/10721.false_positive +++ /dev/null @@ -1,3 +0,0 @@ -Fix a false positive for ``unbalanced-tuple-unpacking`` when a tuple is assigned to a function call and the structure of the function's return value is ambiguous. - -Closes #10721 diff --git a/pylint/__pkginfo__.py b/pylint/__pkginfo__.py index 877091ee89..06357ecb23 100644 --- a/pylint/__pkginfo__.py +++ b/pylint/__pkginfo__.py @@ -9,7 +9,7 @@ from __future__ import annotations -__version__ = "4.0.2" +__version__ = "4.0.3" def get_numversion_from_version(v: str) -> tuple[int, int, int]: diff --git a/tbump.toml b/tbump.toml index c1797cca75..a43bfecc24 100644 --- a/tbump.toml +++ b/tbump.toml @@ -1,7 +1,7 @@ github_url = "https://github.com/pylint-dev/pylint" [version] -current = "4.0.2" +current = "4.0.3" regex = ''' ^(?P0|[1-9]\d*) \.