izulu: The Exceptional Library
izulu is a Python library designed to bring Object-Oriented Programming (OOP) principles into exception and error management. It eliminates the need for manual error message formatting by allowing developers to define exception templates within class definitions. This approach centralizes static error data and uses keyword arguments for variable data, generating final error messages dynamically. The library is actively maintained, with version 0.75.0 being the latest stable release.
Warnings
- gotcha For Python versions prior to 3.11, the 'compatibility' extra must be installed (e.g., `pip install izulu izulu[compatibility]`). For Python 3.11 and newer, `pip install izulu` is sufficient.
- breaking The `__template__` attribute for custom error classes only supports named format fields (e.g., `{reason}`, `{amount}`). Positional (e.g., `{0}`) or empty (e.g., `{}`) format fields are forbidden and will result in a `ValueError` during class definition or instantiation.
- gotcha Type hints (e.g., `amount: int`) on class attributes are not validated or enforced by izulu at runtime. They serve purely as documentation or for static analysis tools.
- gotcha The library's validation behavior is dependent on the 'features' enabled for an error class. Modifying the feature set can lead to different or raw exceptions being raised than expected.
- gotcha While direct inheritance from `izulu.root.Error` is possible, the documentation recommends creating an intermediate base class (e.g., `class BaseError(Error):`) to centrally control default behavior and features for your application's exceptions.
Install
-
pip install izulu -
pip install izulu izulu[compatibility]
Imports
- Error
from izulu.root import Error
- root
from izulu import root
Quickstart
from izulu.root import Error
class DataError(Error):
__template__ = "Invalid data: {reason}"
class MissingField(DataError):
__template__ = "Missing required field: '{field_name}'"
field_name: str
class OutOfRange(DataError):
__template__ = "Value for '{field_name}' is out of range. Expected: {min_val}-{max_val}, Got: {actual_val}"
field_name: str
min_val: int
max_val: int
actual_val: int
def process_data(data: dict):
if not data:
raise DataError(reason="empty input")
if 'name' not in data:
raise MissingField(field_name='name')
age = data.get('age')
if not isinstance(age, int):
raise DataError(reason="age must be an integer")
min_age, max_age = 18, 99
if not (min_age <= age <= max_age):
raise OutOfRange(field_name='age', min_val=min_age, max_val=max_age, actual_val=age)
print(f"Data processed successfully for {data['name']} (Age: {age})")
# Example Usage:
try:
process_data({"name": "Alice", "age": 25})
except DataError as e:
print(f"Error processing data: {e}")
try:
process_data(None)
except DataError as e:
print(f"Error processing data: {e}")
try:
process_data({"name": "Bob"})
except MissingField as e:
print(f"Error processing data: {e}. Field: {e.field_name}")
try:
process_data({"name": "Charlie", "age": 150})
except OutOfRange as e:
print(f"Error processing data: {e}. Details: field={e.field_name}, actual={e.actual_val}")