Deviopath › Python

Bank Ledger with Custom Exceptions

Hard · Errors

Custom exceptions let callers catch exactly the errors they expect. A common pattern is one base class for your module plus specific subclasses, so except LedgerError catches all of them.

1. Define LedgerError(Exception) and three subclasses of it: InvalidAmount, UnknownAccount and InsufficientFunds.

2. Complete Ledger. It starts from a dict of account balances (whole numbers). Checks happen in this order, and a failed operation changes nothing:

- the amount must be an int greater than 0, else raise InvalidAmount("invalid amount: <amount>")

- every account must exist (the source is checked before the target), else raise UnknownAccount("unknown account: <name>")

- the source needs enough money, else raise InsufficientFunds("<source> has <balance>, needs <amount>")

Methods: deposit(name, amount), transfer(source, target, amount), transfer_many(transfers) and balances(), which returns a copy of the balances dict.

transfer_many takes a list of [source, target, amount] and is all-or-nothing. Transfers run in order, so an earlier one can fund a later one. If any of them fails, restore every balance to what it was before the batch and raise that error.

The driver run_ledger(balances, ops) is already written. It catches LedgerError only, so your exceptions must inherit from it.

Next: Limited Concurrency with a Semaphore