Coverage for dataexcept/database_exceptions.py: 100%
30 statements
« prev ^ index » next coverage.py v7.16.0, created at 2026-09-27 14:44 +0000
« prev ^ index » next coverage.py v7.16.0, created at 2026-09-27 14:44 +0000
1"""Custom exceptions for database operations."""
3from __future__ import annotations
5from ._causes import resolve_cause
6from .base import DataExceptError
7from .redaction import redact_url
10class DatabaseError(DataExceptError):
11 """Base exception for database-related errors."""
13 pass
16class DatabaseConnectionError(DatabaseError):
17 """Raised when connecting to the database fails."""
19 def __init__(self, db_url: str, message: str | None = None) -> None:
20 """Initialize DatabaseConnectionError.
22 Args:
23 db_url: Database connection URL.
24 message: Optional custom error message.
25 """
26 # A connection URL routinely carries a username and password.
27 self.db_url = redact_url(db_url)
28 default = f"Failed to connect to database at '{self.db_url}'"
29 super().__init__(message or default)
32class QueryExecutionError(DatabaseError):
33 """Raised when a database query execution fails."""
35 def __init__(
36 self,
37 query: str,
38 original: Exception | None = None,
39 *,
40 cause: Exception | None = None,
41 ) -> None:
42 """Initialize QueryExecutionError.
44 Args:
45 query: SQL query string.
46 original: Legacy alias for ``cause``.
47 cause: Optional underlying exception.
48 """
49 resolved = resolve_cause(cause=cause, original=original)
50 self.query = query
51 self.original = resolved
52 self.cause = resolved
53 msg = f"Query failed: {query}"
54 if resolved:
55 msg += f" ({resolved})"
56 super().__init__(msg)
59class TransactionError(DatabaseError):
60 """Raised when a database transaction fails."""
62 def __init__(
63 self,
64 transaction_id: str | None = None,
65 message: str | None = None,
66 *,
67 cause: Exception | None = None,
68 ) -> None:
69 """Initialize TransactionError.
71 Args:
72 transaction_id: Identifier for the transaction.
73 message: Optional custom error message.
74 cause: Optional underlying exception.
75 """
76 self.transaction_id = transaction_id
77 self.cause = cause
78 default = "Database transaction failed"
79 if transaction_id:
80 default += f" (id={transaction_id})"
81 super().__init__(message or default)
84__all__ = [
85 "DatabaseError",
86 "DatabaseConnectionError",
87 "QueryExecutionError",
88 "TransactionError",
89]