Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend exception-related checks to except* #9197

Merged
merged 15 commits into from
Nov 10, 2023
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
3 changes: 3 additions & 0 deletions doc/whatsnew/fragments/8827.false_negative
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Extend broad-exception-raised and broad-exception-caught to except*.

Closes #8827
5 changes: 4 additions & 1 deletion pylint/checkers/base/basic_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,10 @@ def visit_expr(self, node: nodes.Expr) -> None:
# side effects), else pointless-statement
if (
isinstance(expr, (nodes.Yield, nodes.Await))
or (isinstance(node.parent, nodes.Try) and node.parent.body == [node])
or (
isinstance(node.parent, (nodes.Try, nodes.TryStar))
and node.parent.body == [node]
)
or (isinstance(expr, nodes.Const) and expr.value is Ellipsis)
):
return
Expand Down
4 changes: 4 additions & 0 deletions pylint/checkers/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,10 @@ def visit_compare(self, node: nodes.Compare) -> None:
"catching-non-exception",
"duplicate-except",
)
def visit_trystar(self, node: nodes.TryStar) -> None:
"""Check for empty except*."""
self.visit_try(node)

def visit_try(self, node: nodes.Try) -> None:
"""Check for empty except."""
self._check_try_except_raise(node)
Expand Down
5 changes: 5 additions & 0 deletions tests/functional/b/broad_exception/broad_exception_caught.rc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[EXCEPTIONS]
overgeneral-exceptions=builtins.BaseException,
builtins.Exception,
functional.b.broad_exception.broad_exception_caught.CustomBroadException,
broad_exception_caught.CustomBroadException
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
broad-exception-caught:14:7:14:16::Catching too general exception Exception:INFERENCE
broad-exception-caught:20:7:20:20::Catching too general exception BaseException:INFERENCE
broad-exception-caught:32:7:32:27::Catching too general exception CustomBroadException:INFERENCE
broad-exception-caught:14:7:14:16::Catching too general exception Exception:INFERENCE
broad-exception-caught:20:7:20:20::Catching too general exception BaseException:INFERENCE
broad-exception-caught:32:7:32:27::Catching too general exception CustomBroadException:INFERENCE
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# pylint: disable=missing-docstring
__revision__ = 0

class CustomBroadException(Exception):
pass


class CustomNarrowException(CustomBroadException):
pass


try:
__revision__ += 1
except* Exception: # [broad-exception-caught]
print('error')


try:
__revision__ += 1
except* BaseException: # [broad-exception-caught]
print('error')


try:
__revision__ += 1
except* ValueError:
print('error')


try:
__revision__ += 1
except CustomBroadException: # [broad-exception-caught]
print('error')


try:
__revision__ += 1
except* CustomNarrowException:
print('error')
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[EXCEPTIONS]
overgeneral-exceptions=builtins.BaseException,
builtins.Exception,
functional.b.broad_exception.broad_exception_caught_trystar.CustomBroadException,
broad_exception_caught_trystar.CustomBroadException

[testoptions]
min_pyver=3.11
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
broad-exception-caught:14:8:14:17::Catching too general exception Exception:INFERENCE
broad-exception-caught:20:8:20:21::Catching too general exception BaseException:INFERENCE
broad-exception-caught:32:7:32:27::Catching too general exception CustomBroadException:INFERENCE
5 changes: 5 additions & 0 deletions tests/functional/b/broad_exception/broad_exception_raised.rc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[EXCEPTIONS]
overgeneral-exceptions=builtins.BaseException,
builtins.Exception,
functional.b.broad_exception.broad_exception_raised.CustomBroadException,
broad_exception_raised.CustomBroadException
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
broad-exception-raised:15:4:15:41:exploding_apple:"Raising too general exception: Exception":INFERENCE
broad-exception-raised:20:8:20:34:raise_and_catch:"Raising too general exception: Exception":INFERENCE
broad-exception-caught:21:11:21:20:raise_and_catch:Catching too general exception Exception:INFERENCE
broad-exception-raised:38:8:38:35:raise_catch_raise:"Raising too general exception: Exception":INFERENCE
broad-exception-raised:46:8:46:40:raise_catch_raise_using_alias:"Raising too general exception: Exception":INFERENCE
broad-exception-raised:48:0:48:17::"Raising too general exception: Exception":INFERENCE
broad-exception-raised:49:0:49:21::"Raising too general exception: BaseException":INFERENCE
broad-exception-raised:50:0:50:28::"Raising too general exception: CustomBroadException":INFERENCE
broad-exception-raised:15:4:15:41:exploding_apple:"Raising too general exception: Exception":INFERENCE
broad-exception-raised:20:8:20:34:raise_and_catch:"Raising too general exception: Exception":INFERENCE
broad-exception-caught:21:11:21:20:raise_and_catch:Catching too general exception Exception:INFERENCE
broad-exception-raised:38:8:38:35:raise_catch_raise:"Raising too general exception: Exception":INFERENCE
broad-exception-raised:46:8:46:40:raise_catch_raise_using_alias:"Raising too general exception: Exception":INFERENCE
broad-exception-raised:48:0:48:17::"Raising too general exception: Exception":INFERENCE
broad-exception-raised:49:0:49:21::"Raising too general exception: BaseException":INFERENCE
broad-exception-raised:50:0:50:28::"Raising too general exception: CustomBroadException":INFERENCE
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# pylint: disable=missing-docstring, unreachable

ExceptionAlias = Exception

class CustomBroadException(Exception):
pass


class CustomNarrowException(CustomBroadException):
pass


def exploding_apple(apple):
print(f"{apple} is about to explode")
raise Exception("{apple} exploded !") # [broad-exception-raised]


def raise_and_catch_star():
try:
raise Exception("Oh No!!") # [broad-exception-raised]
except* Exception as ex: # [broad-exception-caught]
print(ex)


def raise_catch_reraise_star():
try:
exploding_apple("apple")
except* Exception as ex:
print(ex)
raise ex


def raise_catch_raise_star():
try:
exploding_apple("apple")
except* Exception as ex:
print(ex)
raise Exception() from None # [broad-exception-raised]


def raise_catch_raise_using_alias_star():
try:
exploding_apple("apple")
except* Exception as ex:
print(ex)
raise ExceptionAlias() from None # [broad-exception-raised]

raise Exception() # [broad-exception-raised]
raise BaseException() # [broad-exception-raised]
raise CustomBroadException() # [broad-exception-raised]
raise IndexError from None
raise CustomNarrowException() from None
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[EXCEPTIONS]
overgeneral-exceptions=builtins.BaseException,
builtins.Exception,
functional.b.broad_exception.broad_exception_raised_trystar.CustomBroadException,
broad_exception_raised_trystar.CustomBroadException
[testoptions]
min_pyver=3.11
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
broad-exception-raised:15:4:15:41:exploding_apple:"Raising too general exception: Exception":INFERENCE
broad-exception-raised:20:8:20:34:raise_and_catch_star:"Raising too general exception: Exception":INFERENCE
broad-exception-caught:21:12:21:21:raise_and_catch_star:Catching too general exception Exception:INFERENCE
broad-exception-raised:38:8:38:35:raise_catch_raise_star:"Raising too general exception: Exception":INFERENCE
broad-exception-raised:46:8:46:40:raise_catch_raise_using_alias_star:"Raising too general exception: Exception":INFERENCE
broad-exception-raised:48:0:48:17::"Raising too general exception: Exception":INFERENCE
broad-exception-raised:49:0:49:21::"Raising too general exception: BaseException":INFERENCE
broad-exception-raised:50:0:50:28::"Raising too general exception: CustomBroadException":INFERENCE
4 changes: 0 additions & 4 deletions tests/functional/b/broad_exception_caught.rc

This file was deleted.

4 changes: 0 additions & 4 deletions tests/functional/b/broad_exception_raised.rc

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class "ExceptionsChecker" as pylint.checkers.exceptions.ExceptionsChecker #44BB9
visit_compare(node: nodes.Compare) -> None
visit_raise(node: nodes.Raise) -> None
visit_try(node: nodes.Try) -> None
visit_trystar(node: nodes.TryStar) -> None
}
class "StdlibChecker" as pylint.checkers.stdlib.StdlibChecker #44BB99 {
msgs : dict[str, MessageDefinitionTuple]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ rankdir=BT
charset="utf-8"
"custom_colors.CheckerCollector" [color="red", fontcolor="black", label=<{CheckerCollector|checker1<br ALIGN="LEFT"/>checker2<br ALIGN="LEFT"/>checker3<br ALIGN="LEFT"/>|}>, shape="record", style="filled"];
"pylint.extensions.check_elif.ElseifUsedChecker" [color="#44BB88", fontcolor="black", label=<{ElseifUsedChecker|msgs : dict<br ALIGN="LEFT"/>name : str<br ALIGN="LEFT"/>|leave_module(_: nodes.Module): None<br ALIGN="LEFT"/>process_tokens(tokens: list[TokenInfo]): None<br ALIGN="LEFT"/>visit_if(node: nodes.If): None<br ALIGN="LEFT"/>}>, shape="record", style="filled"];
"pylint.checkers.exceptions.ExceptionsChecker" [color="yellow", fontcolor="black", label=<{ExceptionsChecker|msgs : dict<br ALIGN="LEFT"/>name : str<br ALIGN="LEFT"/>options : tuple<br ALIGN="LEFT"/>|open(): None<br ALIGN="LEFT"/>visit_binop(node: nodes.BinOp): None<br ALIGN="LEFT"/>visit_compare(node: nodes.Compare): None<br ALIGN="LEFT"/>visit_raise(node: nodes.Raise): None<br ALIGN="LEFT"/>visit_try(node: nodes.Try): None<br ALIGN="LEFT"/>}>, shape="record", style="filled"];
"pylint.checkers.exceptions.ExceptionsChecker" [color="yellow", fontcolor="black", label=<{ExceptionsChecker|msgs : dict<br ALIGN="LEFT"/>name : str<br ALIGN="LEFT"/>options : tuple<br ALIGN="LEFT"/>|open(): None<br ALIGN="LEFT"/>visit_binop(node: nodes.BinOp): None<br ALIGN="LEFT"/>visit_compare(node: nodes.Compare): None<br ALIGN="LEFT"/>visit_raise(node: nodes.Raise): None<br ALIGN="LEFT"/>visit_try(node: nodes.Try): None<br ALIGN="LEFT"/>visit_trystar(node: nodes.TryStar): None<br ALIGN="LEFT"/>}>, shape="record", style="filled"];
"pylint.checkers.stdlib.StdlibChecker" [color="yellow", fontcolor="black", label=<{StdlibChecker|msgs : dict[str, MessageDefinitionTuple]<br ALIGN="LEFT"/>name : str<br ALIGN="LEFT"/>|deprecated_arguments(method: str): tuple[tuple[int \| None, str], ...]<br ALIGN="LEFT"/>deprecated_attributes(): Iterable[str]<br ALIGN="LEFT"/>deprecated_classes(module: str): Iterable[str]<br ALIGN="LEFT"/>deprecated_decorators(): Iterable[str]<br ALIGN="LEFT"/>deprecated_methods(): set[str]<br ALIGN="LEFT"/>visit_boolop(node: nodes.BoolOp): None<br ALIGN="LEFT"/>visit_call(node: nodes.Call): None<br ALIGN="LEFT"/>visit_functiondef(node: nodes.FunctionDef): None<br ALIGN="LEFT"/>visit_if(node: nodes.If): None<br ALIGN="LEFT"/>visit_ifexp(node: nodes.IfExp): None<br ALIGN="LEFT"/>visit_unaryop(node: nodes.UnaryOp): None<br ALIGN="LEFT"/>}>, shape="record", style="filled"];
"pylint.checkers.exceptions.ExceptionsChecker" -> "custom_colors.CheckerCollector" [arrowhead="diamond", arrowtail="none", fontcolor="green", label="checker1", style="solid"];
"pylint.checkers.stdlib.StdlibChecker" -> "custom_colors.CheckerCollector" [arrowhead="diamond", arrowtail="none", fontcolor="green", label="checker3", style="solid"];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class "ExceptionsChecker" as pylint.checkers.exceptions.ExceptionsChecker #yello
visit_compare(node: nodes.Compare) -> None
visit_raise(node: nodes.Raise) -> None
visit_try(node: nodes.Try) -> None
visit_trystar(node: nodes.TryStar) -> None
}
class "StdlibChecker" as pylint.checkers.stdlib.StdlibChecker #yellow {
msgs : dict[str, MessageDefinitionTuple]
Expand Down
Loading