PyCQA / flake8-bugbear

A plugin for Flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle.
MIT License
1.06k stars 104 forks source link

Feature request: a rule for calling super().__init__() in custom exception's __init__() #421

Open m-aciek opened 11 months ago

m-aciek commented 11 months ago
class CustomException(Exception):
    def __init__(self, custom: int, arguments: str) -> None:
        self.msg = f"Something specific happened with custom: {custom} and {arguments}"

Above exception class has an issue, in my personal experience it's quite common. The implementer assumes, that they will use the self.msg parameter during exception handling. The issue araises when the exception gets anywhere else as its string representation is as follows:

>>> raise CustomException(42, 'test')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
__main__.CustomException: (42, 'test')

and when the exception is instantiated with keyword arguments, we lose the information about the arguments' values.

>>> raise CustomException(custom=1, arguments='two')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
__main__.CustomException

How to fix it? By calling super().__init__() in the constructor. That way the string representation of the custom exception will contain the error message.

class CustomException(Exception):
    def __init__(self, custom: int, arguments: str) -> None:
        self.msg = "Something specific happened with custom: {custom} and {arguments}"
        super().__init__(self.msg)
>>> raise CustomException(1, 'two')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
__main__.CustomException: Something specific happened with custom: 1 and two
>>> raise CustomException(custom=1, parameters='two')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
__main__.CustomException: Something specific happened with custom: 1 and two

Specification proposal

If a class:

Then:

cooperlees commented 10 months ago

Should the example be:

class CustomException(Exception):
    def __init__(self, custom: int, arguments: str) -> None:
        self.msg = f"Something specific happened with custom: {custom} and {arguments}"  # <-- custom
         super().__init__(self.msg)

Seems a good check for me and a bug waiting to happen. Please explain why this is bad to do in the README. And as always, provide good tests with correct code and bad code please.

m-aciek commented 10 months ago

Should the example be:

Yes, right, thanks. I fixed the original post.