Skip to content

Commit 63312f8

Browse files
committed
feat(error-handling): enhance error handling with detailed logging and flexible decorator
1 parent e9ce726 commit 63312f8

1 file changed

Lines changed: 21 additions & 30 deletions

File tree

forklet/infrastructure/error_handler.py

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,17 @@
1111
from forklet.infrastructure.logger import logger
1212

1313

14-
15-
1614
####
1715
## DOWNLOAD ERROR MODEL
1816
#####
1917
class DownloadError(Exception):
2018
"""Base exception for download-related errors."""
21-
22-
def __init__(
23-
self,
24-
message: str,
25-
original_error: Optional[Exception] = None
26-
):
19+
20+
def __init__(self, message: str, original_error: Optional[Exception] = None):
2721
super().__init__(message)
2822
self.original_error = original_error
2923
self.message = message
30-
24+
3125
def __str__(self) -> str:
3226
if self.original_error:
3327
return f"{self.message} (Original: {self.original_error})"
@@ -39,6 +33,7 @@ def __str__(self) -> str:
3933
#####
4034
class RateLimitError(DownloadError):
4135
"""Exception raised when rate limits are exceeded."""
36+
4237
pass
4338

4439

@@ -47,6 +42,7 @@ class RateLimitError(DownloadError):
4742
#####
4843
class AuthenticationError(DownloadError):
4944
"""Exception raised for authentication failures."""
45+
5046
pass
5147

5248

@@ -55,20 +51,20 @@ class AuthenticationError(DownloadError):
5551
#####
5652
class RepositoryNotFoundError(DownloadError):
5753
"""Exception raised when repository is not found."""
58-
pass
5954

55+
pass
6056

6157

6258
####
63-
## RROR HANDLER UTILITIES
59+
## ERROR HANDLER UTILITIES
6460
#####
6561
def handle_api_error(func: Callable) -> Callable:
6662
"""
6763
Decorator to handle API errors and convert to appropriate exceptions.
68-
64+
6965
Args:
7066
func: Function to decorate
71-
67+
7268
Returns:
7369
Decorated function
7470
"""
@@ -81,8 +77,7 @@ def wrapper(*args, **kwargs) -> Any:
8177

8278
# Cse of GH Exceptions
8379
except GithubException as e:
84-
85-
if e.status == 403 and 'rate limit' in str(e).lower():
80+
if e.status == 403 and "rate limit" in str(e).lower():
8681
raise RateLimitError("GitHub API rate limit exceeded", e) from e
8782

8883
elif e.status == 401 or e.status == 403:
@@ -96,45 +91,39 @@ def wrapper(*args, **kwargs) -> Any:
9691

9792
# Request Exceptions
9893
except httpx.RequestError as e:
99-
100-
if '429' in str(e) or 'rate limit' in str(e).lower():
94+
if "429" in str(e) or "rate limit" in str(e).lower():
10195
raise RateLimitError("Rate limit exceeded", e) from e
10296

10397
else:
10498
raise DownloadError(f"Network error: {e}", e) from e
10599

106100
except Exception as e:
107101
raise DownloadError(f"Unexpected error: {e}", e) from e
108-
102+
109103
return wrapper
110104

111105

112106
def retry_on_error(max_retries: int = 3) -> Callable:
113107
"""
114108
Decorator to retry operations on specific errors.
115-
109+
116110
Args:
117111
max_retries: Maximum number of retry attempts
118-
112+
119113
Returns:
120-
Decorated function
114+
Decorator function
121115
"""
122116

123117
def decorator(func: Callable) -> Callable:
124-
118+
125119
@functools.wraps(func)
126120
def wrapper(*args, **kwargs) -> Any:
127121
last_exception = None
128-
122+
129123
for attempt in range(max_retries + 1):
130124
try:
131125
return func(*args, **kwargs)
132-
except (
133-
RateLimitError,
134-
httpx.RequestError,
135-
ConnectionError
136-
) as e:
137-
126+
except (RateLimitError, httpx.RequestError, ConnectionError) as e:
138127
last_exception = e
139128
if attempt < max_retries:
140129
logger.warning(
@@ -147,7 +136,9 @@ def wrapper(*args, **kwargs) -> Any:
147136
# Don't retry on other errors
148137
logger.error(f"Non-retryable error: {e}")
149138
raise
150-
139+
151140
raise last_exception or Exception("All retry attempts failed")
141+
152142
return wrapper
143+
153144
return decorator

0 commit comments

Comments
 (0)