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

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

Open
m-aciek opened this issue Nov 10, 2023 · 3 comments

Comments

@m-aciek
Copy link

m-aciek commented Nov 10, 2023

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:

  • inherits from from Exception,
  • doesn't implement own __str__() method,
  • its __init__() method doesn't enforce any positional-only argument,
  • and doesn't call super().__init__() in its __init__() method

Then:

  • new rule should raise an error, calling to fix it.
@cooperlees
Copy link
Collaborator

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
Copy link
Author

m-aciek commented Nov 11, 2023

Should the example be:

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

@jakkdl
Copy link
Contributor

jakkdl commented Oct 28, 2024

This rule could probably also cover python/cpython#125782
i.e. "exception class accepts arguments, but doesn't pass those to super().__init__(..)"

  • inherits from from Exception

we may want to be broader than this, as user exceptions may inherit from any built-in exception - or from other user exceptions that themselves inherit from Exception. This is how I encountered it in the wild
https://github.com/python-trio/trio-websocket/blob/f5fd6d77db16a7b527d670c4045fa1d53e621c35/trio_websocket/_impl.py#L587-L605

Checking inheritance from any built-in exception is fairly straightforward, checking inheritance from any user exception is trickier - one approach is saving exception classes encountered previously in the file, another is to trigger on classes that inherit from *something, and the class name or the super() class name ends with "Exception[Group]" or "Error".

Oh and same goes for Warning classes, in case of -Werror

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants