Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: pylint-dev/pylint
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v3.2.5
Choose a base ref
...
head repository: pylint-dev/pylint
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v3.2.6
Choose a head ref
  • 10 commits
  • 25 files changed
  • 6 contributors

Commits on Jul 7, 2024

  1. Fix invalid-name regression for class attributes in subclasses (#9772

    …) (#9775)
    
    (cherry picked from commit b9a42e8)
    
    Co-authored-by: Jacob Walls <jacobtylerwalls@gmail.com>
    github-actions[bot] and jacobtylerwalls authored Jul 7, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    aea868c View commit details

Commits on Jul 12, 2024

  1. Bump astroid to 3.2.3 (#9787)

    Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
    jacobtylerwalls and Pierre-Sassoulas authored Jul 12, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    9882537 View commit details
  2. Fix FP for unexpected-keyword-arg with ambiguous constructors (#9785)…

    … (#9788)
    github-actions[bot] authored Jul 12, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    8eb2c4d View commit details
  3. Handle assert_never() when imported from typing_extensions (#9782) (#…

    …9790)
    
    (cherry picked from commit a48cd4c)
    jacobtylerwalls authored Jul 12, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    bd4c8f1 View commit details

Commits on Jul 15, 2024

  1. Fix a false positive for missing-param-doc (#9740) (#9793)

    * Fix a false positive for ``missing-param-doc`` where a method which is decorated with ``typing.overload`` was expected to have a docstring specifying its parameters.
    
    Closes #9739
    
    (cherry picked from commit 9cd5c37)
    
    Co-authored-by: Mark Byrne <31762852+mbyrnepr2@users.noreply.github.com>
    github-actions[bot] and mbyrnepr2 authored Jul 15, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    8410f57 View commit details

Commits on Jul 16, 2024

  1. Fix consider-using-min-max-builtin (#9802) (#9803)

    Fix a false positive for `consider-using-min-max-builtin` when the
    assignment target is an attribute.
    
    (cherry picked from commit 6236b91)
    
    Co-authored-by: Ekin Dursun <ekindursun@gmail.com>
    github-actions[bot] and onlined authored Jul 16, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    1d877de View commit details

Commits on Jul 20, 2024

  1. Bump astroid to 3.2.4 (#9816) (#9821)

    (cherry picked from commit c9c768e)
    jacobtylerwalls authored Jul 20, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    c0b1d22 View commit details
  2. Fix a crash when a subclass extends __slots__ (#9817) (#9822)

    (cherry picked from commit 8e18fc0)
    
    Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
    jacobtylerwalls and Pierre-Sassoulas authored Jul 20, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    5f19cd5 View commit details
  3. Update setuptools to >=71.0.4 (#9812) (#9824)

    (cherry picked from commit 60bd230)
    
    Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com>
    github-actions[bot] and cdce8p authored Jul 20, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    810c59c View commit details

Commits on Jul 21, 2024

  1. Bump pylint to 3.2.6, update changelog (#9825)

    jacobtylerwalls authored Jul 21, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    da19566 View commit details
45 changes: 45 additions & 0 deletions doc/whatsnew/3/3.2/index.rst
Original file line number Diff line number Diff line change
@@ -14,6 +14,51 @@ Summary -- Release highlights

.. towncrier release notes start
What's new in Pylint 3.2.6?
---------------------------
Release date: 2024-07-21


False Positives Fixed
---------------------

- Quiet false positives for `unexpected-keyword-arg` when pylint cannot
determine which of two or more dynamically defined classes is being instantiated.

Closes #9672 (`#9672 <https://github.com/pylint-dev/pylint/issues/9672>`_)

- Fix a false positive for ``missing-param-doc`` where a method which is decorated with ``typing.overload`` was expected to have a docstring specifying its parameters.

Closes #9739 (`#9739 <https://github.com/pylint-dev/pylint/issues/9739>`_)

- Fix a regression that raised ``invalid-name`` on class attributes merely
overriding invalid names from an ancestor.

Closes #9765 (`#9765 <https://github.com/pylint-dev/pylint/issues/9765>`_)

- Treat `assert_never()` the same way when imported from `typing_extensions`.

Closes #9780 (`#9780 <https://github.com/pylint-dev/pylint/issues/9780>`_)

- Fix a false positive for `consider-using-min-max-builtin` when the assignment target is an attribute.

Refs #9800 (`#9800 <https://github.com/pylint-dev/pylint/issues/9800>`_)



Other Bug Fixes
---------------

- Fix an `AssertionError` arising from properties that return partial functions.

Closes #9214 (`#9214 <https://github.com/pylint-dev/pylint/issues/9214>`_)

- Fix a crash when a subclass extends ``__slots__``.

Closes #9814 (`#9814 <https://github.com/pylint-dev/pylint/issues/9814>`_)



What's new in Pylint 3.2.5?
---------------------------
Release date: 2024-06-28
2 changes: 1 addition & 1 deletion pylint/__pkginfo__.py
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@

from __future__ import annotations

__version__ = "3.2.5"
__version__ = "3.2.6"


def get_numversion_from_version(v: str) -> tuple[int, int, int]:
4 changes: 3 additions & 1 deletion pylint/checkers/base/name_checker/checker.py
Original file line number Diff line number Diff line change
@@ -491,7 +491,9 @@ def visit_assignname( # pylint: disable=too-many-branches
self._check_name("variable", node.name, node)

# Check names defined in class scopes
elif isinstance(frame, nodes.ClassDef):
elif isinstance(frame, nodes.ClassDef) and not any(
frame.local_attr_ancestors(node.name)
):
if utils.is_enum_member(node) or utils.is_assign_name_annotated_with(
node, "Final"
):
6 changes: 5 additions & 1 deletion pylint/checkers/classes/class_checker.py
Original file line number Diff line number Diff line change
@@ -1486,7 +1486,11 @@ def _check_slots(self, node: nodes.ClassDef) -> None:
if "__slots__" not in node.locals:
return

for slots in node.ilookup("__slots__"):
try:
inferred_slots = tuple(node.ilookup("__slots__"))
except astroid.InferenceError:
return
for slots in inferred_slots:
# check if __slots__ is a valid type
if isinstance(slots, util.UninferableBase):
continue
12 changes: 4 additions & 8 deletions pylint/checkers/refactoring/refactoring_checker.py
Original file line number Diff line number Diff line change
@@ -919,11 +919,9 @@ def get_node_name(node: nodes.NodeNG) -> str:
"""Obtain simplest representation of a node as a string."""
if isinstance(node, nodes.Name):
return node.name # type: ignore[no-any-return]
if isinstance(node, nodes.Attribute):
return node.attrname # type: ignore[no-any-return]
if isinstance(node, nodes.Const):
return str(node.value)
# this is a catch-all for nodes that are not of type Name or Attribute
# this is a catch-all for nodes that are not of type Name or Const
# extremely helpful for Call or BinOp
return node.as_string() # type: ignore[no-any-return]

@@ -944,13 +942,11 @@ def get_node_name(node: nodes.NodeNG) -> str:
# is of type name or attribute. Attribute referring to NamedTuple.x perse.
# So we have to check that target is of these types

if hasattr(target, "name"):
target_assignation = target.name
elif hasattr(target, "attrname"):
target_assignation = target.attrname
else:
if not (hasattr(target, "name") or hasattr(target, "attrname")):
return

target_assignation = get_node_name(target)

if len(node.test.ops) > 1:
return
operator, right_statement = node.test.ops[0]
2 changes: 1 addition & 1 deletion pylint/checkers/typecheck.py
Original file line number Diff line number Diff line change
@@ -1437,7 +1437,7 @@ def visit_call(self, node: nodes.Call) -> None:
"""Check that called functions/methods are inferred to callable objects,
and that passed arguments match the parameters in the inferred function.
"""
called = safe_infer(node.func)
called = safe_infer(node.func, compare_constructors=True)

self._check_not_callable(node, called)

26 changes: 26 additions & 0 deletions pylint/checkers/utils.py
Original file line number Diff line number Diff line change
@@ -1346,6 +1346,7 @@ def safe_infer(
context: InferenceContext | None = None,
*,
compare_constants: bool = False,
compare_constructors: bool = False,
) -> InferenceResult | None:
"""Return the inferred value for the given node.
@@ -1354,6 +1355,9 @@ def safe_infer(
If compare_constants is True and if multiple constants are inferred,
unequal inferred values are also considered ambiguous and return None.
If compare_constructors is True and if multiple classes are inferred,
constructors with different signatures are held ambiguous and return None.
"""
inferred_types: set[str | None] = set()
try:
@@ -1386,6 +1390,13 @@ def safe_infer(
and function_arguments_are_ambiguous(inferred, value)
):
return None
if (
compare_constructors
and isinstance(inferred, nodes.ClassDef)
and isinstance(value, nodes.ClassDef)
and class_constructors_are_ambiguous(inferred, value)
):
return None
except astroid.InferenceError:
return None # There is some kind of ambiguity
except StopIteration:
@@ -1434,6 +1445,21 @@ def function_arguments_are_ambiguous(
return False


def class_constructors_are_ambiguous(
class1: nodes.ClassDef, class2: nodes.ClassDef
) -> bool:
try:
constructor1 = class1.local_attr("__init__")[0]
constructor2 = class2.local_attr("__init__")[0]
except astroid.NotFoundError:
return False
if not isinstance(constructor1, nodes.FunctionDef):
return False
if not isinstance(constructor2, nodes.FunctionDef):
return False
return function_arguments_are_ambiguous(constructor1, constructor2)


def has_known_bases(
klass: nodes.ClassDef, context: InferenceContext | None = None
) -> bool:
5 changes: 2 additions & 3 deletions pylint/checkers/variables.py
Original file line number Diff line number Diff line change
@@ -32,7 +32,7 @@
is_sys_guard,
overridden_method,
)
from pylint.constants import PY39_PLUS, PY311_PLUS, TYPING_NEVER, TYPING_NORETURN
from pylint.constants import PY39_PLUS, TYPING_NEVER, TYPING_NORETURN
from pylint.interfaces import CONTROL_FLOW, HIGH, INFERENCE, INFERENCE_FAILURE
from pylint.typing import MessageDefinitionTuple

@@ -944,8 +944,7 @@ def _defines_name_raises_or_returns(name: str, node: nodes.NodeNG) -> bool:
if utils.is_terminating_func(node.value):
return True
if (
PY311_PLUS
and isinstance(node.value.func, nodes.Name)
isinstance(node.value.func, nodes.Name)
and node.value.func.name == "assert_never"
):
return True
3 changes: 3 additions & 0 deletions pylint/extensions/docparams.py
Original file line number Diff line number Diff line change
@@ -196,6 +196,9 @@ def visit_functiondef(self, node: nodes.FunctionDef) -> None:
:param node: Node for a function or method definition in the AST
:type node: :class:`astroid.scoped_nodes.Function`
"""
if checker_utils.is_overload_stub(node):
return

node_doc = utils.docstringify(
node.doc_node, self.linter.config.default_docstring_type
)
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[build-system]
requires = ["setuptools>=66.1"]
requires = ["setuptools>=71.0.4"]
build-backend = "setuptools.build_meta"

[project]
@@ -41,7 +41,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>=3.2.2,<=3.3.0-dev0",
"astroid>=3.2.4,<=3.3.0-dev0",
"isort>=4.2.5,<6,!=5.13.0",
"mccabe>=0.6,<0.8",
"tomli>=1.1.0;python_version<'3.11'",
4 changes: 2 additions & 2 deletions requirements_test_min.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.[testutils,spelling]
# astroid dependency is also defined in pyproject.toml
astroid==3.2.2 # Pinned to a specific version for tests
astroid==3.2.4 # Pinned to a specific version for tests
typing-extensions~=4.11
py~=1.11.0
pytest~=7.4
@@ -9,4 +9,4 @@ pytest-timeout~=2.3
towncrier~=23.11
requests
# Voluntary for test purpose, not actually used in prod, see #8904
setuptools==41.6.0
setuptools;python_version>='3.12'
2 changes: 1 addition & 1 deletion tbump.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
github_url = "https://github.com/pylint-dev/pylint"

[version]
current = "3.2.5"
current = "3.2.6"
regex = '''
^(?P<major>0|[1-9]\d*)
\.
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ consider-using-max-builtin:26:0:27:19::Consider using 'value3 = max(value3, valu
consider-using-min-builtin:29:0:30:18::Consider using 'value2 = min(value2, value)' instead of unnecessary if block:UNDEFINED
consider-using-min-builtin:32:0:33:25::Consider using 'value = min(value, float(value3))' instead of unnecessary if block:UNDEFINED
consider-using-min-builtin:36:0:37:27::Consider using 'value2 = min(value2, offset + value)' instead of unnecessary if block:UNDEFINED
consider-using-min-builtin:45:0:46:17::Consider using 'value = min(value, 10)' instead of unnecessary if block:UNDEFINED
consider-using-min-builtin:45:0:46:17::Consider using 'A1.value = min(A1.value, 10)' instead of unnecessary if block:UNDEFINED
consider-using-min-builtin:69:0:70:11::Consider using 'A1 = min(A1, A2)' instead of unnecessary if block:UNDEFINED
consider-using-max-builtin:72:0:73:11::Consider using 'A2 = max(A2, A1)' instead of unnecessary if block:UNDEFINED
consider-using-min-builtin:75:0:76:11::Consider using 'A1 = min(A1, A2)' instead of unnecessary if block:UNDEFINED
34 changes: 33 additions & 1 deletion tests/functional/ext/docparams/missing_param_doc.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
#pylint: disable=missing-module-docstring
#pylint: disable=missing-module-docstring, too-few-public-methods


from typing import overload, Union


def foobar1(arg1, arg2): #[missing-any-param-doc]
"""function foobar ...
@@ -207,3 +211,31 @@ def foobar19(one, two, **kwargs):
"""
print(one, two, kwargs)
return 1


class Word:
"""
Methods decorated with `typing.overload` are excluded
from the docparam checks. For example: `missing-param-doc` and
`missing-type-doc`.
"""
def __init__(self, word):
self.word = word

@overload
def starts_with(self, letter: None) -> None: ...

@overload
def starts_with(self, letter: str) -> bool: ...

def starts_with(self, letter: Union[str, None]) -> Union[bool, None]:
"""
Returns:
True if `self.word` begins with `letter`
Args:
letter: str
"""
if self.word:
return self.word.startswith(letter)
return None
30 changes: 15 additions & 15 deletions tests/functional/ext/docparams/missing_param_doc.txt
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
missing-any-param-doc:3:0:3:11:foobar1:"Missing any documentation in ""foobar1""":HIGH
missing-any-param-doc:8:0:8:11:foobar2:"Missing any documentation in ""foobar2""":HIGH
missing-param-doc:15:0:15:11:foobar3:"""arg2"" missing in parameter documentation":HIGH
missing-type-doc:15:0:15:11:foobar3:"""arg2"" missing in parameter type documentation":HIGH
missing-param-doc:24:0:24:11:foobar4:"""arg2"" missing in parameter documentation":HIGH
missing-type-doc:24:0:24:11:foobar4:"""arg2"" missing in parameter type documentation":HIGH
missing-type-doc:33:0:33:11:foobar5:"""arg1"" missing in parameter type documentation":HIGH
missing-param-doc:43:0:43:11:foobar6:"""arg3"" missing in parameter documentation":HIGH
missing-type-doc:43:0:43:11:foobar6:"""arg3"" missing in parameter type documentation":HIGH
missing-any-param-doc:53:0:53:11:foobar7:"Missing any documentation in ""foobar7""":HIGH
missing-any-param-doc:61:0:61:11:foobar8:"Missing any documentation in ""foobar8""":HIGH
missing-type-doc:76:0:76:12:foobar10:"""arg1, arg3"" missing in parameter type documentation":HIGH
missing-any-param-doc:88:0:88:12:foobar11:"Missing any documentation in ""foobar11""":HIGH
missing-param-doc:97:0:97:12:foobar12:"""arg3"" missing in parameter documentation":HIGH
missing-type-doc:97:0:97:12:foobar12:"""arg2, arg3"" missing in parameter type documentation":HIGH
missing-any-param-doc:7:0:7:11:foobar1:"Missing any documentation in ""foobar1""":HIGH
missing-any-param-doc:12:0:12:11:foobar2:"Missing any documentation in ""foobar2""":HIGH
missing-param-doc:19:0:19:11:foobar3:"""arg2"" missing in parameter documentation":HIGH
missing-type-doc:19:0:19:11:foobar3:"""arg2"" missing in parameter type documentation":HIGH
missing-param-doc:28:0:28:11:foobar4:"""arg2"" missing in parameter documentation":HIGH
missing-type-doc:28:0:28:11:foobar4:"""arg2"" missing in parameter type documentation":HIGH
missing-type-doc:37:0:37:11:foobar5:"""arg1"" missing in parameter type documentation":HIGH
missing-param-doc:47:0:47:11:foobar6:"""arg3"" missing in parameter documentation":HIGH
missing-type-doc:47:0:47:11:foobar6:"""arg3"" missing in parameter type documentation":HIGH
missing-any-param-doc:57:0:57:11:foobar7:"Missing any documentation in ""foobar7""":HIGH
missing-any-param-doc:65:0:65:11:foobar8:"Missing any documentation in ""foobar8""":HIGH
missing-type-doc:80:0:80:12:foobar10:"""arg1, arg3"" missing in parameter type documentation":HIGH
missing-any-param-doc:92:0:92:12:foobar11:"Missing any documentation in ""foobar11""":HIGH
missing-param-doc:101:0:101:12:foobar12:"""arg3"" missing in parameter documentation":HIGH
missing-type-doc:101:0:101:12:foobar12:"""arg2, arg3"" missing in parameter type documentation":HIGH
7 changes: 7 additions & 0 deletions tests/functional/i/invalid/invalid_name.py
Original file line number Diff line number Diff line change
@@ -102,3 +102,10 @@ def test_disable_mixed(
"""Invalid-name will still be raised for other arguments."""
self.foo_bar = fooBar
self.foo_bar2 = fooBar2

def tearDown(self): ... # pylint: disable=invalid-name


class FooBarSubclass(FooBar):
tearDown = FooBar.tearDown
tearDownNotInAncestor = None # [invalid-name]
2 changes: 2 additions & 0 deletions tests/functional/i/invalid/invalid_name.rc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[MAIN]
class-attribute-naming-style=snake_case
1 change: 1 addition & 0 deletions tests/functional/i/invalid/invalid_name.txt
Original file line number Diff line number Diff line change
@@ -6,3 +6,4 @@ invalid-name:66:0:66:68:a_very_very_very_long_function_name_WithCamelCase_to_mak
invalid-name:74:23:74:29:FooBar.__init__:"Argument name ""fooBar"" doesn't conform to snake_case naming style":HIGH
invalid-name:80:8:80:14:FooBar.func1:"Argument name ""fooBar"" doesn't conform to snake_case naming style":HIGH
invalid-name:100:8:100:15:FooBar.test_disable_mixed:"Argument name ""fooBar2"" doesn't conform to snake_case naming style":HIGH
invalid-name:111:4:111:25:FooBarSubclass:"Class attribute name ""tearDownNotInAncestor"" doesn't conform to snake_case naming style":HIGH
3 changes: 1 addition & 2 deletions tests/functional/r/recursion/recursion_error_3159.py
Original file line number Diff line number Diff line change
@@ -13,8 +13,7 @@ def initialize_options(self):
def finalize_options(self):
pass

@staticmethod
def run():
def run(self):
print("Do anything")


14 changes: 14 additions & 0 deletions tests/functional/s/slots_checks.py
Original file line number Diff line number Diff line change
@@ -128,3 +128,17 @@ class Parent:

class ChildNotAffectedByValueInSlot(Parent):
__slots__ = ('first', )


# https://github.com/pylint-dev/pylint/issues/9814
class SlotsManipulationTest:
__slots__ = ["a", "b", "c"]


class TestChild(SlotsManipulationTest):
__slots__ += ["d", "e", "f"] # pylint: disable=undefined-variable


t = TestChild()

print(t.__slots__)
Loading