Presenting “izulu”#
Bring OOP into exception/error management#
You can read docs from top to bottom or jump straight into “Quickstart” section. For details note “Specifications” sections below.
Neat #1: Stop messing with raw strings and manual message formatting#
if not data:
raise ValueError("Data is invalid: no data")
amount = data["amount"]
if amount < 0:
raise ValueError(f"Data is invalid: amount can't be negative ({amount})")
elif amount > 1000:
raise ValueError(f"Data is invalid: amount is too large ({amount})")
if data["status"] not in {"READY", "IN_PROGRESS"}:
raise ValueError("Data is invalid: unprocessable status")
With izulu you can forget about manual error message management all over the codebase!
class ValidationError(Error):
__template__ = "Data is invalid: {reason}"
reason: str
class AmountValidationError(ValidationError):
__template__ = "Invalid amount: {amount}"
amount: int
if not data:
raise ValidationError(reason="no data")
amount = data["amount"]
if amount < 0:
raise AmountValidationError(reason="amount can't be negative", amount=amount)
elif amount > 1000:
raise AmountValidationError(reason="amount is too large", amount=amount)
if data["status"] not in {"READY", "IN_PROGRESS"}:
raise ValidationError(reason="unprocessable status")
Provide only variable data for error instantiations. Keep static data within error class.
Under the hood kwargs are used to format __template__ into final error message.
Neat #2: Attribute errors with useful fields#
from falcon import HTTPBadRequest
class AmountValidationError(ValidationError):
__template__ = "Data is invalid: {reason} ({amount})"
reason: str
amount: int
try:
validate(data)
except AmountValidationError as e:
if e.amount < 0:
raise HTTPBadRequest(f"Bad amount: {e.amount}")
raise
Annotated instance attributes automatically populated from kwargs.
Neat #3: Static and dynamic defaults#
class AmountValidationError(ValidationError):
__template__ = "Data is invalid: {reason} ({amount}; MAX={_MAX}) at {ts}"
_MAX: ClassVar[int] = 1000
amount: int
reason: str = "amount is too large"
ts: datetime = factory(datetime.now)
print(AmountValidationError(amount=15000))
# Data is invalid: amount is too large (15000; MAX=1000) at 2024-01-13 22:59:25.132699
print(AmountValidationError(amount=-1, reason="amount can't be negative"))
# Data is invalid: amount can't be negative (-1; MAX=1000) at 2024-01-13 22:59:54.482577