What is the standard way to design exception inheritance?

Viewed 42

Im having some trouble with designing the exception classes for a Python web API. What I would like to do is have various exceptions set up with some default error codes/messages, but also allow the flexibility of creating a custom one.

Take the following code:

class APIException(Exception):
    def __init__(self):
        super().__init__(self.message)

    @property
    def message(self) -> str:
        raise NotImplementedError

    @property
    def code(self) -> int:
        raise NotImplementedError

    @property
    def response(self):
        return {"error": self.message}, self.code


class UnknownException(APIException):
    message = "An unknown error occurred."
    code = 500


class UnauthorizedException(APIException):
    message = "Unauthorized"
    code = 401

This allows me to do things like raise UnauthorizedException, which work fine. However, what I would like to be able to do is to raise arbitrary API exceptions, like raise APIException("This is a custom error", 404). Raising a set exception with arguments and raising an APIException without arguments do not need to be supported; I will not be raising them like that.

It doesn't seem I can do this cleanly with the way I have designed the inheritance above. I have tried other various approaches but none seem to be as clean as the example above.

What would be the best way to go about doing this sort of thing?

1 Answers

Have your APIException constructor take arguments, and have the subclasses implement constructors that provide those arguments:

class APIException(Exception):
    def __init__(self, message, code):
        super().__init__(message)
        self.message = message
        self.code = code

    @property
    def response(self):
        return {"error": self.message}, self.code


class UnknownException(APIException):
    def __init__():
        super().__init__("An unknown error occurred.", 500)


class UnauthorizedException(APIException):
    def __init__():
        super().__init__("Unauthorized", 401)
Related