Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions doc/data/messages/b/break-in-finally/bad.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
while True:
try:
pass
finally:
break # [break-in-finally]
7 changes: 7 additions & 0 deletions doc/data/messages/b/break-in-finally/good.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
while True:
try:
pass
except ValueError:
pass
else:
break
2 changes: 2 additions & 0 deletions doc/data/messages/b/break-in-finally/related.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- `Python 3 docs 'finally' clause <https://docs.python.org/3/reference/compound_stmts.html#finally-clause>`_
- `PEP 765 - Disallow return/break/continue that exit a finally block <https://peps.python.org/pep-0765/>`_
1 change: 0 additions & 1 deletion doc/data/messages/c/continue-in-finally/details.rst

This file was deleted.

2 changes: 0 additions & 2 deletions doc/data/messages/c/continue-in-finally/pylintrc

This file was deleted.

2 changes: 2 additions & 0 deletions doc/data/messages/c/continue-in-finally/related.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- `Python 3 docs 'finally' clause <https://docs.python.org/3/reference/compound_stmts.html#finally-clause>`_
- `PEP 765 - Disallow return/break/continue that exit a finally block <https://peps.python.org/pep-0765/>`_
1 change: 1 addition & 0 deletions doc/data/messages/r/return-in-finally/related.rst
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
- `Python 3 docs 'finally' clause <https://docs.python.org/3/reference/compound_stmts.html#finally-clause>`_
- `PEP 765 - Disallow return/break/continue that exit a finally block <https://peps.python.org/pep-0765/>`_
9 changes: 6 additions & 3 deletions doc/user_guide/checkers/features.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,6 @@ Basic checker Messages
Used when break or continue keywords are used outside a loop.
:function-redefined (E0102): *%s already defined line %s*
Used when a function / class / method is redefined.
:continue-in-finally (E0116): *'continue' not supported inside 'finally' clause*
Emitted when the `continue` keyword is found inside a finally clause, which
is a SyntaxError.
:abstract-class-instantiated (E0110): *Abstract class %r with abstract methods instantiated*
Used when an abstract class with `abc.ABCMeta` as metaclass has abstract
methods and is instantiated.
Expand Down Expand Up @@ -108,6 +105,12 @@ Basic checker Messages
Used when a break or a return statement is found inside the finally clause of
a try...finally block: the exceptions raised in the try clause will be
silently swallowed instead of being re-raised.
:break-in-finally (W0137): *'break' discouraged inside 'finally' clause*
Emitted when the `break` keyword is found inside a finally clause. This
will raise a SyntaxWarning starting in Python 3.14.
:continue-in-finally (W0136): *'continue' discouraged inside 'finally' clause*
Emitted when the `continue` keyword is found inside a finally clause. This
will raise a SyntaxWarning starting in Python 3.14.
:return-in-finally (W0134): *'return' shadowed by the 'finally' clause.*
Emitted when a 'return' statement is found in a 'finally' block. This will
overwrite the return value of a function and should be avoided.
Expand Down
3 changes: 2 additions & 1 deletion doc/user_guide/messages/messages_overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ All messages in the error category:
error/broken-noreturn
error/catching-non-exception
error/class-variable-slots-conflict
error/continue-in-finally
error/declare-non-slot
error/dict-iter-missing-items
error/duplicate-argument-name
Expand Down Expand Up @@ -223,13 +222,15 @@ All messages in the warning category:
warning/bare-except
warning/binary-op-exception
warning/boolean-datetime
warning/break-in-finally
warning/broad-exception-caught
warning/broad-exception-raised
warning/cell-var-from-loop
warning/comparison-with-callable
warning/confusing-with-statement
warning/consider-ternary-expression
warning/contextmanager-generator-missing-cleanup
warning/continue-in-finally
warning/dangerous-default-value
warning/deprecated-argument
warning/deprecated-attribute
Expand Down
5 changes: 5 additions & 0 deletions doc/whatsnew/fragments/10480.breaking
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
The message-id of ``continue-in-finally`` was changed from ``E0116`` to ``W0136``. The warning is
now emitted for every Python version since it will raise a syntax warning in Python 3.14.
See `PEP 765 - Disallow return/break/continue that exit a finally block <https://peps.python.org/pep-0765/>`_.

Refs #10480
5 changes: 5 additions & 0 deletions doc/whatsnew/fragments/10480.new_check
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Add ``break-in-finally`` warning. Using ``break`` inside the ``finally`` clause
will raise a syntax warning in Python 3.14.
See `PEP 765 - Disallow return/break/continue that exit a finally block <https://peps.python.org/pep-0765/>`_.

Refs #10480
33 changes: 21 additions & 12 deletions pylint/checkers/base/basic_error_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,12 +182,6 @@ class BasicErrorChecker(_BasicChecker):
"nonlocal-and-global",
"Emitted when a name is both nonlocal and global.",
),
"E0116": (
"'continue' not supported inside 'finally' clause",
"continue-in-finally",
"Emitted when the `continue` keyword is found "
"inside a finally clause, which is a SyntaxError.",
),
"E0117": (
"nonlocal name %s found without binding",
"nonlocal-without-binding",
Expand All @@ -201,12 +195,22 @@ class BasicErrorChecker(_BasicChecker):
"which results in an error since Python 3.6.",
{"minversion": (3, 6)},
),
"W0136": (
"'continue' discouraged inside 'finally' clause",
"continue-in-finally",
"Emitted when the `continue` keyword is found "
"inside a finally clause. This will raise a SyntaxWarning "
"starting in Python 3.14.",
),
"W0137": (
"'break' discouraged inside 'finally' clause",
"break-in-finally",
"Emitted when the `break` keyword is found "
"inside a finally clause. This will raise a SyntaxWarning "
"starting in Python 3.14.",
),
}

def open(self) -> None:
py_version = self.linter.config.py_version
self._py38_plus = py_version >= (3, 8)

@utils.only_required_for_messages("function-redefined")
def visit_classdef(self, node: nodes.ClassDef) -> None:
self._check_redefinition("class", node)
Expand Down Expand Up @@ -369,7 +373,7 @@ def visit_yieldfrom(self, node: nodes.YieldFrom) -> None:
def visit_continue(self, node: nodes.Continue) -> None:
self._check_in_loop(node, "continue")

@utils.only_required_for_messages("not-in-loop")
@utils.only_required_for_messages("not-in-loop", "break-in-finally")
def visit_break(self, node: nodes.Break) -> None:
self._check_in_loop(node, "break")

Expand Down Expand Up @@ -497,9 +501,14 @@ def _check_in_loop(
isinstance(parent, nodes.Try)
and node in parent.finalbody
and isinstance(node, nodes.Continue)
and not self._py38_plus
):
self.add_message("continue-in-finally", node=node)
if (
isinstance(parent, nodes.Try)
and node in parent.finalbody
and isinstance(node, nodes.Break)
):
self.add_message("break-in-finally", node=node)

self.add_message("not-in-loop", node=node, args=node_name)

Expand Down
8 changes: 7 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,13 @@ tests/functional/m/member/member_checks_async.py,\
testpaths = [ "tests" ]
python_files = [ "*test_*.py" ]
addopts = "--strict-markers"
filterwarnings = "error"
filterwarnings = [
"error",
# Added in Python 3.14
"ignore:'break' in a 'finally' block:SyntaxWarning",
"ignore:'return' in a 'finally' block:SyntaxWarning",
"ignore:'continue' in a 'finally' block:SyntaxWarning",
]
markers = [
"primer_stdlib: Checks for crashes and errors when running pylint on stdlib",
"benchmark: Baseline of pylint performance, if this regress something serious happened",
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/c/continue_in_finally.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
try:
pass
finally:
break
break # [break-in-finally]

while True:
try:
Expand Down
2 changes: 0 additions & 2 deletions tests/functional/c/continue_in_finally.rc

This file was deleted.

3 changes: 2 additions & 1 deletion tests/functional/c/continue_in_finally.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
continue-in-finally:9:8:9:16::'continue' not supported inside 'finally' clause:UNDEFINED
continue-in-finally:9:8:9:16::'continue' discouraged inside 'finally' clause:UNDEFINED
break-in-finally:15:8:15:13::'break' discouraged inside 'finally' clause:UNDEFINED
Loading