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.2
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.3
Choose a head ref
  • 4 commits
  • 15 files changed
  • 4 contributors

Commits on Jun 4, 2024

  1. Fix a false positive for redefined-outer-name (#9678) (#9695)

    When there is a name defined in an exception-handling block which shares the same name
    as a local variable that has been defined in a function body. Check if the outer node is in the
    scope of an exception assignment and do not emit ``redefined-outer-name`` if that is the case.
    
    Closes #9671
    
    (cherry picked from commit 57ae027)
    
    Co-authored-by: Mark Byrne <31762852+mbyrnepr2@users.noreply.github.com>
    github-actions[bot] and mbyrnepr2 authored Jun 4, 2024

    Verified

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

Commits on Jun 5, 2024

  1. [multiple-statements] Make pylint compatible with black's 2024 style (#…

    …9697) (#9698)
    
    * Add more test cases to cover pass / ...
    * Define the confidence as HIGH
    * Exclude the class with Ellipsis from the check
    
    Closes #9398
    
    (cherry picked from commit afd5edf)
    
    Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
    github-actions[bot] and Pierre-Sassoulas authored Jun 5, 2024

    Verified

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

Commits on Jun 6, 2024

  1. Fix false positive in use-yield-from when using yield return (#9700

    …) (#9701)
    
    If the return value from `yield` is inspected inline, such as by
    (augmented) assignment, changing the looped `yield` to `yield from` is
    very likely to change the semantics of the generator, since there is an
    implicit use of `generator.send`.
    
    Closes #9696
    
    (cherry picked from commit ea73bae)
    
    Co-authored-by: Jake Lishman <jake.lishman@ibm.com>
    github-actions[bot] and jakelishman authored Jun 6, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    8aba7d1 View commit details
  2. Bump pylint to 3.2.3, update changelog

    Pierre-Sassoulas committed Jun 6, 2024

    Verified

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

.. towncrier release notes start
What's new in Pylint 3.2.3?
---------------------------
Release date: 2024-06-06


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

- Classes with only an Ellipsis (``...``) in their body do not trigger 'multiple-statements'
anymore if they are inlined (in accordance with black's 2024 style).

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

- Fix a false positive for ``redefined-outer-name`` when there is a name defined in an exception-handling block which shares the same name as a local variable that has been defined in a function body.

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

- Fix a false positive for ``use-yield-from`` when using the return value from the ``yield`` atom.

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



What's new in Pylint 3.2.2?
---------------------------
Release date: 2024-05-20
4 changes: 2 additions & 2 deletions examples/pylintrc
Original file line number Diff line number Diff line change
@@ -87,8 +87,8 @@ load-plugins=
# Pickle collected data for later comparisons.
persistent=yes

# Resolve imports to .pyi stubs if available. May reduce no-member messages
# and increase not-an-iterable messages.
# Resolve imports to .pyi stubs if available. May reduce no-member messages and
# increase not-an-iterable messages.
prefer-stubs=no

# Minimum Python version to use for version dependent checks. Will default to
6 changes: 3 additions & 3 deletions examples/pyproject.toml
Original file line number Diff line number Diff line change
@@ -77,9 +77,9 @@ limit-inference-results = 100
# Pickle collected data for later comparisons.
persistent = true

# Resolve imports to .pyi stubs if available. May reduce no-member messages
# and increase not-an-iterable messages.
prefer-stubs = false
# Resolve imports to .pyi stubs if available. May reduce no-member messages and
# increase not-an-iterable messages.
# prefer-stubs =

# Minimum Python version to use for version dependent checks. Will default to the
# version used to run pylint.
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.2"
__version__ = "3.2.3"


def get_numversion_from_version(v: str) -> tuple[int, int, int]:
11 changes: 5 additions & 6 deletions pylint/checkers/format.py
Original file line number Diff line number Diff line change
@@ -522,9 +522,8 @@ def visit_default(self, node: nodes.NodeNG) -> None:

def _check_multi_statement_line(self, node: nodes.NodeNG, line: int) -> None:
"""Check for lines containing multiple statements."""
# Do not warn about multiple nested context managers
# in with statements.
if isinstance(node, nodes.With):
# Do not warn about multiple nested context managers in with statements.
return
if (
isinstance(node.parent, nodes.If)
@@ -539,16 +538,16 @@ def _check_multi_statement_line(self, node: nodes.NodeNG, line: int) -> None:
):
return

# Functions stubs with ``Ellipsis`` as body are exempted.
# Functions stubs and class with ``Ellipsis`` as body are exempted.
if (
isinstance(node.parent, nodes.FunctionDef)
and isinstance(node, nodes.Expr)
isinstance(node, nodes.Expr)
and isinstance(node.parent, (nodes.FunctionDef, nodes.ClassDef))
and isinstance(node.value, nodes.Const)
and node.value.value is Ellipsis
):
return

self.add_message("multiple-statements", node=node)
self.add_message("multiple-statements", node=node, confidence=HIGH)
self._visited_lines[line] = 2

def check_trailing_whitespace_ending(self, line: str, i: int) -> None:
15 changes: 9 additions & 6 deletions pylint/checkers/refactoring/refactoring_checker.py
Original file line number Diff line number Diff line change
@@ -1169,21 +1169,24 @@ def visit_yield(self, node: nodes.Yield) -> None:
if not isinstance(node.value, nodes.Name):
return

parent = node.parent.parent
loop_node = node.parent.parent
if (
not isinstance(parent, nodes.For)
or isinstance(parent, nodes.AsyncFor)
or len(parent.body) != 1
not isinstance(loop_node, nodes.For)
or isinstance(loop_node, nodes.AsyncFor)
or len(loop_node.body) != 1
# Avoid a false positive if the return value from `yield` is used,
# (such as via Assign, AugAssign, etc).
or not isinstance(node.parent, nodes.Expr)
):
return

if parent.target.name != node.value.name:
if loop_node.target.name != node.value.name:
return

if isinstance(node.frame(), nodes.AsyncFunctionDef):
return

self.add_message("use-yield-from", node=parent, confidence=HIGH)
self.add_message("use-yield-from", node=loop_node, confidence=HIGH)

@staticmethod
def _has_exit_in_scope(scope: nodes.LocalsDictNodeNG) -> bool:
9 changes: 9 additions & 0 deletions pylint/checkers/variables.py
Original file line number Diff line number Diff line change
@@ -1519,6 +1519,15 @@ def visit_functiondef(self, node: nodes.FunctionDef) -> None:
):
continue

# Suppress emitting the message if the outer name is in the
# scope of an exception assignment.
# For example: the `e` in `except ValueError as e`
global_node = globs[name][0]
if isinstance(global_node, nodes.AssignName) and isinstance(
global_node.parent, nodes.ExceptHandler
):
continue

line = definition.fromlineno
if not self._is_name_ignored(stmt, name):
self.add_message(
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.2"
current = "3.2.3"
regex = '''
^(?P<major>0|[1-9]\d*)
\.
15 changes: 15 additions & 0 deletions tests/functional/m/multiple_statements.py
Original file line number Diff line number Diff line change
@@ -4,13 +4,28 @@

from typing import overload

if True: print("Golfing sure is nice") # [multiple-statements]
if True: pass # [multiple-statements]
if True: ... # [multiple-statements]

if True: print("Golfing sure is nice") # [multiple-statements]
else:
pass

if True: pass # [multiple-statements]
else:
pass

if True: ... # [multiple-statements]
else:
pass

# The following difference in behavior is due to black 2024's style
# that reformat pass on multiple line but reformat "..." on a single line
# (only for classes, not for the examples above)
class MyException(Exception): print("Golfing sure is nice") # [multiple-statements]
class MyError(Exception): pass # [multiple-statements]
class DebugTrueDetected(Exception): ...

class MyError(Exception): a='a' # [multiple-statements]

15 changes: 10 additions & 5 deletions tests/functional/m/multiple_statements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
multiple-statements:7:9:7:13::More than one statement on a single line:UNDEFINED
multiple-statements:9:9:9:13::More than one statement on a single line:UNDEFINED
multiple-statements:13:26:13:30:MyError:More than one statement on a single line:UNDEFINED
multiple-statements:15:26:15:31:MyError:More than one statement on a single line:UNDEFINED
multiple-statements:17:26:17:31:MyError:More than one statement on a single line:UNDEFINED
multiple-statements:7:9:7:38::More than one statement on a single line:HIGH
multiple-statements:8:9:8:13::More than one statement on a single line:HIGH
multiple-statements:9:9:9:12::More than one statement on a single line:HIGH
multiple-statements:11:9:11:38::More than one statement on a single line:HIGH
multiple-statements:15:9:15:13::More than one statement on a single line:HIGH
multiple-statements:19:9:19:12::More than one statement on a single line:HIGH
multiple-statements:26:30:26:59:MyException:More than one statement on a single line:HIGH
multiple-statements:27:26:27:30:MyError:More than one statement on a single line:HIGH
multiple-statements:30:26:30:31:MyError:More than one statement on a single line:HIGH
multiple-statements:32:26:32:31:MyError:More than one statement on a single line:HIGH
15 changes: 14 additions & 1 deletion tests/functional/m/multiple_statements_single_line.py
Original file line number Diff line number Diff line change
@@ -4,19 +4,32 @@

from typing import overload

if True: print("Golfing sure is nice")
if True: pass
if True: ...

if True: print("Golfing sure is nice") # [multiple-statements]
else:
pass

if True: pass # [multiple-statements]
else:
pass

if True: ... # [multiple-statements]
else:
pass

class MyException(Exception): print("Golfing sure is nice")
class MyError(Exception): pass
class DebugTrueDetected(Exception): ...


class MyError(Exception): a='a'

class MyError(Exception): a='a'; b='b' # [multiple-statements]

try:
try: #@
pass
except:
pass
6 changes: 4 additions & 2 deletions tests/functional/m/multiple_statements_single_line.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
multiple-statements:9:9:9:13::More than one statement on a single line:UNDEFINED
multiple-statements:17:26:17:31:MyError:More than one statement on a single line:UNDEFINED
multiple-statements:11:9:11:38::More than one statement on a single line:HIGH
multiple-statements:15:9:15:13::More than one statement on a single line:HIGH
multiple-statements:19:9:19:12::More than one statement on a single line:HIGH
multiple-statements:30:26:30:31:MyError:More than one statement on a single line:HIGH
22 changes: 22 additions & 0 deletions tests/functional/r/redefined/redefined_except_handler.py
Original file line number Diff line number Diff line change
@@ -70,3 +70,25 @@ def func():
# pylint:disable-next=invalid-name, unused-variable
except IOError as CustomException: # [redefined-outer-name]
pass


# https://github.com/pylint-dev/pylint/issues/9671
def function_before_exception():
"""The local variable `e` should not trigger `redefined-outer-name`
when `e` is also defined in the subsequent exception handling block.
"""
e = 42
return e

try:
raise ValueError('outer')
except ValueError as e:
print(e)


def function_after_exception():
"""The local variable `e` should not trigger `redefined-outer-name`
when `e` is also defined in the preceding exception handling block.
"""
e = 42
return e
10 changes: 10 additions & 0 deletions tests/functional/u/use/use_yield_from.py
Original file line number Diff line number Diff line change
@@ -57,3 +57,13 @@ async def async_for_yield(agen):
async def async_yield(agen):
for item in agen:
yield item


# If the return from `yield` is used inline, don't suggest delegation.

def yield_use_send():
for item in (1, 2, 3):
_ = yield item
total = 0
for item in (1, 2, 3):
total += yield item
2 changes: 1 addition & 1 deletion towncrier.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[tool.towncrier]
version = "3.2.2"
version = "3.2.3"
directory = "doc/whatsnew/fragments"
filename = "doc/whatsnew/3/3.2/index.rst"
template = "doc/whatsnew/fragments/_template.rst"