|
15 | 15 |
|
16 | 16 | from pylint import checkers
|
17 | 17 | from pylint.checkers import utils
|
| 18 | +from pylint.interfaces import HIGH |
18 | 19 | from pylint.typing import MessageDefinitionTuple
|
19 | 20 |
|
20 | 21 | if TYPE_CHECKING:
|
@@ -131,13 +132,13 @@ def _is_raising(body: list) -> bool:
|
131 | 132 | "try-except-raise block!",
|
132 | 133 | ),
|
133 | 134 | "W0707": (
|
134 |
| - "Consider explicitly re-raising using the 'from' keyword", |
| 135 | + "Consider explicitly re-raising using %s'%s from %s'", |
135 | 136 | "raise-missing-from",
|
136 |
| - "Python 3's exception chaining means it shows the traceback of the " |
137 |
| - "current exception, but also the original exception. Not using `raise " |
138 |
| - "from` makes the traceback inaccurate, because the message implies " |
139 |
| - "there is a bug in the exception-handling code itself, which is a " |
140 |
| - "separate situation than wrapping an exception.", |
| 137 | + "Python's exception chaining shows the traceback of the current exception, " |
| 138 | + "but also of the original exception. When you raise a new exception after " |
| 139 | + "another exception was caught it's likely that the second exception is a " |
| 140 | + "friendly re-wrapping of the first exception. In such cases `raise from` " |
| 141 | + "provides a better link between the two tracebacks in the final error.", |
141 | 142 | ),
|
142 | 143 | "W0711": (
|
143 | 144 | 'Exception to catch is the result of a binary "%s" operation',
|
@@ -334,16 +335,33 @@ def _check_raise_missing_from(self, node: nodes.Raise) -> None:
|
334 | 335 | if containing_except_node.name is None:
|
335 | 336 | # The `except` doesn't have an `as exception:` part, meaning there's no way that
|
336 | 337 | # the `raise` is raising the same exception.
|
337 |
| - self.add_message("raise-missing-from", node=node) |
338 |
| - elif isinstance(node.exc, nodes.Call) and isinstance(node.exc.func, nodes.Name): |
339 |
| - # We have a `raise SomeException(whatever)`. |
340 |
| - self.add_message("raise-missing-from", node=node) |
| 338 | + class_of_old_error = "Exception" |
| 339 | + if isinstance(containing_except_node.type, (nodes.Name, nodes.Tuple)): |
| 340 | + # 'except ZeroDivisionError' or 'except (ZeroDivisionError, ValueError)' |
| 341 | + class_of_old_error = containing_except_node.type.as_string() |
| 342 | + self.add_message( |
| 343 | + "raise-missing-from", |
| 344 | + node=node, |
| 345 | + args=( |
| 346 | + f"'except {class_of_old_error} as exc' and ", |
| 347 | + node.as_string(), |
| 348 | + "exc", |
| 349 | + ), |
| 350 | + confidence=HIGH, |
| 351 | + ) |
341 | 352 | elif (
|
342 |
| - isinstance(node.exc, nodes.Name) |
| 353 | + isinstance(node.exc, nodes.Call) |
| 354 | + and isinstance(node.exc.func, nodes.Name) |
| 355 | + or isinstance(node.exc, nodes.Name) |
343 | 356 | and node.exc.name != containing_except_node.name.name
|
344 | 357 | ):
|
345 |
| - # We have a `raise SomeException`. |
346 |
| - self.add_message("raise-missing-from", node=node) |
| 358 | + # We have a `raise SomeException(whatever)` or a `raise SomeException` |
| 359 | + self.add_message( |
| 360 | + "raise-missing-from", |
| 361 | + node=node, |
| 362 | + args=("", node.as_string(), containing_except_node.name.name), |
| 363 | + confidence=HIGH, |
| 364 | + ) |
347 | 365 |
|
348 | 366 | def _check_catching_non_exception(self, handler, exc, part):
|
349 | 367 | if isinstance(exc, nodes.Tuple):
|
|
0 commit comments