Source code for wsqlite.exceptions
"""Custom exceptions for wsqlite library."""
[docs]
class WSQLiteError(Exception):
"""Base exception for wsqlite library.
All other wsqlite exceptions inherit from this class.
"""
[docs]
def __init__(self, message: str, details: dict = None):
self.message = message
self.details = details or {}
super().__init__(self.message)
[docs]
class ConnectionError(WSQLiteError):
"""Exception raised for connection-related errors.
Examples:
- Database file not found
- Permission denied
- Invalid connection parameters
"""
pass
class PoolExhaustedError(ConnectionError):
"""Raised when connection pool is exhausted and all connections are in use.
This typically indicates:
- Pool size too small for the workload
- Connections not being returned to pool properly
- Long-running queries blocking connections
Suggestions:
- Increase pool max_size
- Use connection context managers properly
- Optimize slow queries
- Reduce transaction scope
"""
def __init__(self, max_size: int, timeout: float = 30.0):
self.max_size = max_size
self.timeout = timeout
message = (
f"Connection pool exhausted (max={max_size} connections). "
f"Timeout after {timeout}s. "
"Consider: increasing pool size, reducing contention, or optimizing queries."
)
super().__init__(message, {"max_size": max_size, "timeout": timeout})
class DatabaseLockedError(ConnectionError):
"""Raised when database is locked by another connection or process.
SQLite uses database-level locking. This error occurs when:
- Multiple processes trying to write simultaneously
- Long-running write transactions
- Unclosed connections from previous operations
Suggestions:
- Retry with exponential backoff
- Use WAL mode (enabled by default)
- Reduce transaction size
- Ensure connections are properly closed
"""
def __init__(self, operation: str, query: str = None):
self.operation = operation
self.query = query
message = (
f"Database locked during '{operation}'. "
"Another process may be writing. Consider retrying."
)
super().__init__(message, {"operation": operation, "query": query})
[docs]
class TableSyncError(WSQLiteError):
"""Exception raised during table synchronization operations.
Examples:
- Failed to create table
- Column type mismatch during sync
- Invalid index creation
"""
pass
[docs]
class ValidationError(WSQLiteError):
"""Exception raised for data validation failures.
Examples:
- Invalid field type for Pydantic model
- Missing required field
- Field validation rule violation
"""
pass
[docs]
class OperationError(WSQLiteError):
"""Exception raised for general database operation failures.
This is a catch-all for database errors that don't fit other categories.
Examples:
- Query syntax error
- Constraint violation
- Foreign key violation
- Unique constraint violation
"""
[docs]
def __init__(self, message: str, query: str = None, params: tuple = None):
self.query = query
self.params = params
details = {"query": query, "params": params} if query else {}
super().__init__(message, details)
[docs]
class SQLInjectionError(WSQLiteError):
"""Raised when potential SQL injection is detected.
This is a security feature. The library validates all identifiers
(table names, column names) to prevent SQL injection attacks.
Only alphanumeric characters and underscores are allowed in identifiers.
"""
[docs]
def __init__(self, identifier: str):
self.identifier = identifier
message = (
f"Invalid or potentially dangerous SQL identifier detected: '{identifier}'. "
"Identifiers must start with a letter or underscore and contain only "
"alphanumeric characters and underscores."
)
super().__init__(message, {"identifier": identifier})
[docs]
class TransactionError(WSQLiteError):
"""Exception raised for transaction-related errors.
Examples:
- Transaction already committed
- Transaction already rolled back
- Nested transactions not supported
- Savepoint errors
"""
pass
class MigrationError(WSQLiteError):
"""Exception raised during database migration operations.
Examples:
- Migration version conflict
- Failed to apply migration
- Rollback failed
- Missing migration file
"""
def __init__(self, message: str, version: int = None, direction: str = None):
self.version = version
self.direction = direction
details = {"version": version, "direction": direction} if version else {}
super().__init__(message, details)
class QueryError(WSQLiteError):
"""Exception raised for query execution errors.
This includes:
- Syntax errors
- Type errors
- Constraint violations
- Missing tables/columns
"""
def __init__(self, message: str, query: str = None, original_error: Exception = None):
self.query = query
self.original_error = original_error
details = {"query": query}
if original_error:
details["original_error"] = str(original_error)
super().__init__(message, details)
class TimeoutError(WSQLiteError):
"""Exception raised when an operation times out.
This can occur when:
- Query takes too long
- Lock acquisition times out
- Connection pool times out
"""
def __init__(self, operation: str, timeout: float):
self.operation = operation
self.timeout = timeout
message = (
f"Operation '{operation}' timed out after {timeout}s. "
"Consider optimizing the query or increasing the timeout."
)
super().__init__(message, {"operation": operation, "timeout": timeout})
__all__ = [
"WSQLiteError",
"ConnectionError",
"PoolExhaustedError",
"DatabaseLockedError",
"TableSyncError",
"ValidationError",
"OperationError",
"SQLInjectionError",
"TransactionError",
"MigrationError",
"QueryError",
"TimeoutError",
]