Skip to content

Commit 77a3340

Browse files
committed
!squash
1 parent 4274b23 commit 77a3340

File tree

1 file changed

+132
-24
lines changed

1 file changed

+132
-24
lines changed

notes/2025-03-08 - test-audit - test plan.md

Lines changed: 132 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1263,47 +1263,84 @@ All code examples in this plan follow these guidelines and must be maintained th
12631263
12641264
import logging
12651265
import time
1266-
import typing as t
1266+
from typing import Any, Dict, Optional, Union, Tuple, List, TypeVar, cast
12671267
from urllib.parse import urlparse
1268+
import dataclasses
12681269
12691270
import requests
12701271
from requests.exceptions import ConnectionError, Timeout
12711272
1272-
from vcspull.exc import NetworkError
1273+
from vcspull.exc import NetworkError, ErrorCode
12731274
12741275
log = logging.getLogger(__name__)
12751276
12761277
1278+
@dataclasses.dataclass
12771279
class RetryStrategy:
12781280
"""Strategy for retrying network operations."""
12791281
1280-
def __init__(self, max_retries=3, initial_delay=1.0, backoff_factor=2.0):
1281-
self.max_retries = max_retries
1282-
self.initial_delay = initial_delay
1283-
self.backoff_factor = backoff_factor
1282+
max_retries: int = 3
1283+
initial_delay: float = 1.0
1284+
backoff_factor: float = 2.0
1285+
1286+
def get_delay(self, attempt: int) -> float:
1287+
"""
1288+
Get delay for a specific retry attempt.
12841289
1285-
def get_delay(self, attempt):
1286-
"""Get delay for a specific retry attempt."""
1290+
Parameters
1291+
----------
1292+
attempt : int
1293+
Current attempt number (1-based)
1294+
1295+
Returns
1296+
-------
1297+
float
1298+
Delay in seconds
1299+
"""
12871300
return self.initial_delay * (self.backoff_factor ** (attempt - 1))
12881301
12891302
1303+
ResponseType = TypeVar('ResponseType')
1304+
1305+
12901306
class NetworkManager:
12911307
"""Manager for network operations."""
12921308
1293-
def __init__(self, session=None, retry_strategy=None):
1309+
def __init__(
1310+
self,
1311+
*,
1312+
session: Optional[requests.Session] = None,
1313+
retry_strategy: Optional[RetryStrategy] = None
1314+
) -> None:
1315+
"""
1316+
Initialize network manager.
1317+
1318+
Parameters
1319+
----------
1320+
session : requests.Session, optional
1321+
Session to use for requests
1322+
retry_strategy : RetryStrategy, optional
1323+
Strategy for retrying failed requests
1324+
"""
12941325
self.session = session or requests.Session()
12951326
self.retry_strategy = retry_strategy or RetryStrategy()
12961327
1297-
def request(self, method, url, **kwargs):
1298-
"""Perform HTTP request with retry logic.
1328+
def request(
1329+
self,
1330+
method: str,
1331+
url: str,
1332+
**kwargs: Any
1333+
) -> requests.Response:
1334+
"""
1335+
Perform HTTP request with retry logic.
12991336
13001337
Parameters
13011338
----------
13021339
method : str
13031340
HTTP method (GET, POST, etc.)
13041341
url : str
13051342
URL to request
1306-
**kwargs
1343+
**kwargs : Any
13071344
Additional parameters for requests
13081345
13091346
Returns
@@ -1324,7 +1361,7 @@ All code examples in this plan follow these guidelines and must be maintained th
13241361
13251362
# Initialize retry counter
13261363
attempt = 0
1327-
last_exception = None
1364+
last_exception: Optional[NetworkError] = None
13281365
13291366
while attempt < max_retries:
13301367
attempt += 1
@@ -1340,7 +1377,8 @@ All code examples in this plan follow these guidelines and must be maintained th
13401377
f"Server error: {response.status_code}",
13411378
url=url,
13421379
status_code=response.status_code,
1343-
retry_count=attempt
1380+
retry_count=attempt,
1381+
error_code=ErrorCode.NETWORK_UNREACHABLE
13441382
)
13451383
continue
13461384
elif response.status_code == 429:
@@ -1349,7 +1387,8 @@ All code examples in this plan follow these guidelines and must be maintained th
13491387
"Rate limited",
13501388
url=url,
13511389
status_code=429,
1352-
retry_count=attempt
1390+
retry_count=attempt,
1391+
error_code=ErrorCode.RATE_LIMITED
13531392
)
13541393
# Get retry-after header if available
13551394
retry_after = response.headers.get('Retry-After')
@@ -1368,7 +1407,8 @@ All code examples in this plan follow these guidelines and must be maintained th
13681407
raise NetworkError(
13691408
f"Client error: {response.status_code}",
13701409
url=url,
1371-
status_code=response.status_code
1410+
status_code=response.status_code,
1411+
error_code=ErrorCode.NETWORK_UNREACHABLE
13721412
)
13731413
13741414
# Success
@@ -1380,7 +1420,11 @@ All code examples in this plan follow these guidelines and must be maintained th
13801420
last_exception = NetworkError(
13811421
f"Network error: {str(e)}",
13821422
url=url,
1383-
retry_count=attempt
1423+
retry_count=attempt,
1424+
error_code=(
1425+
ErrorCode.TIMEOUT if isinstance(e, Timeout)
1426+
else ErrorCode.CONNECTION_REFUSED
1427+
)
13841428
)
13851429
13861430
# Wait before retrying
@@ -1393,19 +1437,83 @@ All code examples in this plan follow these guidelines and must be maintained th
13931437
if last_exception:
13941438
raise last_exception
13951439
else:
1396-
raise NetworkError(f"Failed after {max_retries} attempts", url=url)
1440+
raise NetworkError(
1441+
f"Failed after {max_retries} attempts",
1442+
url=url,
1443+
error_code=ErrorCode.NETWORK_UNREACHABLE
1444+
)
1445+
1446+
def get(
1447+
self,
1448+
url: str,
1449+
**kwargs: Any
1450+
) -> requests.Response:
1451+
"""
1452+
Perform HTTP GET request.
1453+
1454+
Parameters
1455+
----------
1456+
url : str
1457+
URL to request
1458+
**kwargs : Any
1459+
Additional parameters for requests
13971460
1398-
def get(self, url, **kwargs):
1399-
"""Perform HTTP GET request."""
1461+
Returns
1462+
-------
1463+
requests.Response
1464+
Response object
1465+
"""
14001466
return self.request('GET', url, **kwargs)
14011467
1402-
def post(self, url, **kwargs):
1403-
"""Perform HTTP POST request."""
1468+
def post(
1469+
self,
1470+
url: str,
1471+
**kwargs: Any
1472+
) -> requests.Response:
1473+
"""
1474+
Perform HTTP POST request.
1475+
1476+
Parameters
1477+
----------
1478+
url : str
1479+
URL to request
1480+
**kwargs : Any
1481+
Additional parameters for requests
1482+
1483+
Returns
1484+
-------
1485+
requests.Response
1486+
Response object
1487+
"""
14041488
return self.request('POST', url, **kwargs)
14051489
14061490
1407-
def perform_request(url, auth=None, retry_strategy=None, **kwargs):
1408-
"""Perform HTTP request with configurable retry strategy."""
1491+
def perform_request(
1492+
url: str,
1493+
*,
1494+
auth: Optional[Tuple[str, str]] = None,
1495+
retry_strategy: Optional[RetryStrategy] = None,
1496+
**kwargs: Any
1497+
) -> requests.Response:
1498+
"""
1499+
Perform HTTP request with configurable retry strategy.
1500+
1501+
Parameters
1502+
----------
1503+
url : str
1504+
URL to request
1505+
auth : Tuple[str, str], optional
1506+
Authentication credentials (username, password)
1507+
retry_strategy : RetryStrategy, optional
1508+
Strategy for retrying failed requests
1509+
**kwargs : Any
1510+
Additional parameters for requests
1511+
1512+
Returns
1513+
-------
1514+
requests.Response
1515+
Response object
1516+
"""
14091517
manager = NetworkManager(retry_strategy=retry_strategy)
14101518
return manager.get(url, auth=auth, **kwargs)
14111519
```

0 commit comments

Comments
 (0)