from typing import Optional class GCPError(Exception): def __init__(self, message: str, cause: Optional[Exception] = None) -> None: super().__init__(message) self.cause = cause def __str__(self) -> str: base = super().__str__() return f"{base} (caused by: {self.cause})" if self.cause else base class AuthenticationError(GCPError): pass class ResourceNotFoundError(GCPError): def __init__(self, resource_type: str, name: str) -> None: super().__init__(f"{resource_type} not found: {name}") self.resource_type = resource_type self.name = name class QuotaExceededError(GCPError): pass class PermissionDeniedError(GCPError): pass class RetryableError(GCPError): def __init__(self, message: str, attempt: int, cause: Optional[Exception] = None) -> None: super().__init__(message, cause) self.attempt = attempt class TimeoutError(GCPError): pass