except ShopError ловит ShopError и всех её наследников. PaymentError унаследована
напрямую от Exception — она не в ветке магазина, поэтому проходит мимо и попадает
в except Exception как неизвестная ошибка. Когда все ошибки приложения наследуют
от одной базовой, обработчик ловит их одной строкой, а новые ошибки попадают туда автоматически.
Эталонное решение
class ShopError(Exception):
"""Базовая ошибка магазина."""
class OutOfStockError(ShopError):
"""Товара недостаточно на складе."""
class PaymentError(ShopError):
"""Не удалось провести оплату."""
def place_order(card):
if card == "0000":
raise PaymentError("банк отклонил карту")
if card == "1111":
raise OutOfStockError("товар закончился")
def handle(card):
try:
place_order(card)
except ShopError as e:
return 400, str(e)
except Exception:
return 500, "внутренняя ошибка"
return 201, "заказ оформлен"
print(handle("0000"))