Skip to content

My Guidelines

General Guidelines

  1. The core module of any project must separate the data model from application code.
  2. The public API of any project must be:
    • Minimalist
    • Generalist
    • Extensible
  3. Only throw exceptions from API functions. Never from helper functions.

Exceptions

System exceptions x Application exceptions

A zero value division error is a system exception. But if your program needs an input argument to be greater than 10, then that is an application exception.

Recoverable exception x Unrecoverable exception

All exceptions can be gracefully handled if we know the list of exceptions that can happen.

However, if our code uses external libraries that call other libraries and so on we might be in a situation that is very difficult to tell what exceptions can be raised.

There is a general guideline that says to not use a bare exception, or, to not use a catch-all exceptions because that pattern hides bugs. Nonetheless, sometimes we are forced to use because otherwise the application will crash and we don't want to offer that experience to our users.

Here are some guidelines to deal with these issues:

  1. Catch specific exceptions and handle them separately. Create exception classes if necessary.
  2. If program termination is not an option, use a catch-all block at the end of the list and log it the exception properly. As soon as the exception is determined, create a specific block for that exception in the production code.
Note

In python, you can simply use a bare raise statement to re-raise the current exception from a catch block.

A function that throws multiple Exceptions

I have a function that can throw multiple exceptions. I want to handle each of them differently. Therefore, I cannot use the same exception type for each of the exception thrown. Therefore, how can I avoid to creating custom exception classes in this case?

For example, I have a function that sets two attributes. These operations can raise a ValueError, but I would like to distinguish between one and the other. In particular, imagine that I have a CLI that consumes my API. I would like to give the ability to the client to specify their own custom messages according to the error that was thrown.

Python Exception base class

This class is the one recommended to be inherit by custom Exceptions. You can pass several arguments to it and they will be print in the exception message.

>>> raise Exception("an error occurred", "unexpected value", 42)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Exception: ('an error occurred', 'unexpected value', 42)

Chainning Exceptions

Use the from statement to specify the __cause__ of an exception. You can use from None to hide previous exceptions that were raised in the backtrace.

>>> try:
...     result = 42 / 0
... except Exception as error:
...     raise ValueError("operation not allowed") from error
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
ValueError: operation not allowed

Exception guidelines

  1. Do not hide system exceptions from the user.
  2. Throw exceptions from API functions.
  3. Do not use a catch-all clause because this hide bugs.
  4. Caution when throwing exceptions that might reveal sensitive information (such as personable identifiable information)
  5. Use the Error suffix when naming your custom error exception classes.
  6. Identify errors as soon as possible. Raise exceptions if necessary conditions are not valid.