-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
152 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
"""Timeout configuration for API requests.""" | ||
|
||
from dataclasses import dataclass | ||
from typing import Union, Tuple | ||
|
||
|
||
@dataclass | ||
class TimeoutConfig: | ||
"""Configuration for request timeouts. | ||
:param connect: How long to wait for the connection to be established (seconds) | ||
:param read: How long to wait for the server to send data (seconds) | ||
""" | ||
connect: float = 3.05 # Default connect timeout | ||
read: float = 27.0 # Default read timeout | ||
|
||
def __post_init__(self): | ||
"""Validate timeout values.""" | ||
if self.connect <= 0: | ||
raise ValueError("connect timeout must be greater than 0") | ||
if self.read <= 0: | ||
raise ValueError("read timeout must be greater than 0") | ||
|
||
@property | ||
def as_tuple(self) -> Tuple[float, float]: | ||
"""Get timeout configuration as a tuple. | ||
:return: Tuple of (connect_timeout, read_timeout) | ||
""" | ||
return (self.connect, self.read) | ||
|
||
@classmethod | ||
def from_total(cls, total: float) -> 'TimeoutConfig': | ||
"""Create a TimeoutConfig from a total timeout value. | ||
:param total: Total timeout in seconds, will be split between connect and read | ||
:return: TimeoutConfig instance | ||
:raises ValueError: If total timeout is less than or equal to 0 | ||
""" | ||
if total <= 0: | ||
raise ValueError("total timeout must be greater than 0") | ||
# Allocate 10% to connect timeout and 90% to read timeout | ||
return cls(connect=total * 0.1, read=total * 0.9) | ||
|
||
@classmethod | ||
def default(cls) -> 'TimeoutConfig': | ||
"""Get the default timeout configuration. | ||
:return: TimeoutConfig instance with default values | ||
""" | ||
return cls() | ||
|
||
def __str__(self) -> str: | ||
"""Get string representation of timeout configuration.""" | ||
return f"TimeoutConfig(connect={self.connect:.2f}s, read={self.read:.2f}s)" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
"""Tests for timeout configuration.""" | ||
|
||
import unittest | ||
from bcra_connector.timeout_config import TimeoutConfig | ||
|
||
|
||
class TestTimeoutConfig(unittest.TestCase): | ||
"""Test suite for the TimeoutConfig class.""" | ||
|
||
def test_default_values(self): | ||
"""Test default timeout values.""" | ||
config = TimeoutConfig() | ||
self.assertEqual(config.connect, 3.05) | ||
self.assertEqual(config.read, 27.0) | ||
|
||
def test_custom_values(self): | ||
"""Test custom timeout values.""" | ||
config = TimeoutConfig(connect=5.0, read=30.0) | ||
self.assertEqual(config.connect, 5.0) | ||
self.assertEqual(config.read, 30.0) | ||
|
||
def test_invalid_values(self): | ||
"""Test invalid timeout values.""" | ||
with self.assertRaises(ValueError): | ||
TimeoutConfig(connect=0) | ||
with self.assertRaises(ValueError): | ||
TimeoutConfig(connect=-1) | ||
with self.assertRaises(ValueError): | ||
TimeoutConfig(read=0) | ||
with self.assertRaises(ValueError): | ||
TimeoutConfig(read=-1) | ||
|
||
def test_from_total(self): | ||
"""Test creating TimeoutConfig from total timeout.""" | ||
config = TimeoutConfig.from_total(10.0) | ||
self.assertEqual(config.connect, 1.0) # 10% of total | ||
self.assertEqual(config.read, 9.0) # 90% of total | ||
|
||
def test_invalid_total(self): | ||
"""Test invalid total timeout values.""" | ||
with self.assertRaises(ValueError): | ||
TimeoutConfig.from_total(0) | ||
with self.assertRaises(ValueError): | ||
TimeoutConfig.from_total(-1) | ||
|
||
def test_as_tuple(self): | ||
"""Test getting timeout as tuple.""" | ||
config = TimeoutConfig(connect=2.0, read=20.0) | ||
self.assertEqual(config.as_tuple, (2.0, 20.0)) | ||
|
||
def test_default_factory(self): | ||
"""Test default timeout factory method.""" | ||
config = TimeoutConfig.default() | ||
self.assertEqual(config.connect, 3.05) | ||
self.assertEqual(config.read, 27.0) | ||
|
||
def test_string_representation(self): | ||
"""Test string representation of TimeoutConfig.""" | ||
config = TimeoutConfig(connect=2.0, read=20.0) | ||
self.assertEqual(str(config), "TimeoutConfig(connect=2.00s, read=20.00s)") |