Need an error that describes a condition specific to your package? Define a custom exception type. It gives users a named exception to catch and an informative message to help them debug their code. section 12.5 section 12.5.4
Inherit from Exception, not BaseException. For a package, first create a package-specific base exception, then derive more specific exceptions from it so users can catch either one condition or every package error. section 12.5.3 section 12.6
Listing 12.16 Defining a custom exception class
class FileExtensionError(TaskierError):
def __init__(self, file_path):
super().__init__()
self.file_path = file_path
def __str__(self):
return f"The file ({self.file_path}) doesn't appear to be a
CSV file."
# In another part of our package
from pathlib import Path
def upload_file(file_path):
path = Path(file_path)
if path.suffix.lower() != ".csv":
raise FileExtensionError(file_path)
else:
print(f"Processing the file at {file_path}")
A package base class can remain empty, while a specialized exception stores an argument, formats its message with __str__, and is raised when validation fails. section 12.5.3
Rejecting a non-CSV upload
FileExtensionError(TaskierError) stores the supplied file path and reports that the file is not a CSV file. upload_file raises it when the path suffix is not .csv; a caller catches that specific exception and prints the message. A valid tasks.csv file continues processing, while tasks.docx produces the custom diagnostic. section 12.5.3
Use custom exceptions deliberately:
- Prefer built-in exceptions such as ValueError or ZeroDivisionError when they adequately describe the problem. section 12.5.4
- Add custom exceptions when a library or package needs more specific conditions and messages for its users. section 12.5
- Document exceptions that functions may raise, including custom exceptions defined by the module. section 6.5.4


