Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .codegen.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{ "engineHash": "6f9492d", "specHash": "131c54a", "version": "10.12.0" }
{ "engineHash": "ed5236c", "specHash": "131c54a", "version": "10.12.0" }
30 changes: 14 additions & 16 deletions box_sdk_gen/networking/box_network_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class APIRequest:
data: Optional[Union[str, ByteStream, MultipartEncoder]]
content_type: Optional[str] = None
allow_redirects: bool = True
timeout: Optional[Tuple[Optional[float], Optional[float]]] = None
timeout: Optional[Union[float, Tuple[Optional[float], Optional[float]]]] = None


@dataclass
Expand Down Expand Up @@ -189,36 +189,34 @@ def _prepare_request(
@staticmethod
def _get_request_timeout(
options: 'FetchOptions',
) -> Optional[Tuple[Optional[float], Optional[float]]]:
) -> Optional[Union[float, Tuple[Optional[float], Optional[float]]]]:
"""
Derive requests timeout tuple (connect, read) in seconds.
Derive requests timeout in seconds.

Uses `options.network_session.timeout_config` when present.
The timeout config values are expected to be in milliseconds.

Returns a tuple (connect, read) when both timeouts are specified,
a single float when only one is set, or None to use no timeout.
"""
network_session = options.network_session
timeout_config = network_session.timeout_config if network_session else None
if timeout_config is None:
return None

connection_timeout_ms, read_timeout_ms = (
timeout_config.connection_timeout_ms,
timeout_config.read_timeout_ms,
)
connection_timeout_ms = timeout_config.connection_timeout_ms
read_timeout_ms = timeout_config.read_timeout_ms

if connection_timeout_ms is None and read_timeout_ms is None:
return None

connection_timeout_sec = (
connection_timeout_ms / 1000.0
if connection_timeout_ms is not None
else None
)
read_timeout_sec = (
read_timeout_ms / 1000.0 if read_timeout_ms is not None else None
)
if connection_timeout_ms is not None and read_timeout_ms is not None:
return (connection_timeout_ms / 1000.0, read_timeout_ms / 1000.0)

if connection_timeout_ms is not None:
return connection_timeout_ms / 1000.0

return (connection_timeout_sec, read_timeout_sec)
return read_timeout_ms / 1000.0

@staticmethod
def _prepare_headers(
Expand Down
2 changes: 1 addition & 1 deletion box_sdk_gen/networking/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def __init__(
data_sanitizer = DataSanitizer()
if timeout_config is None:
timeout_config = TimeoutConfig(
connection_timeout_ms=5000,
connection_timeout_ms=10000,
read_timeout_ms=60000,
)
self.additional_headers = additional_headers
Expand Down
7 changes: 6 additions & 1 deletion docs/client.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,13 @@ new_client = client.with_custom_base_urls(

In order to configure timeout for API calls, calling the `client.with_timeouts(config)` method creates a new client with timeout settings, leaving the original client unmodified.

All timeout values are in milliseconds.

```python
timeout_config = TimeoutConfig(connection_timeout_ms=10000, read_timeout_ms=30000)
timeout_config = TimeoutConfig(
connection_timeout_ms=5000,
read_timeout_ms=30000,
)
new_client = client.with_timeouts(timeout_config)
```

Expand Down
14 changes: 10 additions & 4 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,14 +194,19 @@ client = BoxClient(auth=auth, network_session=network_session)
## Timeouts

You can configure network timeouts with `TimeoutConfig` on `NetworkSession`.
Python SDK supports separate connection and read timeout values in milliseconds.
The SDK supports two timeout values, both in milliseconds:

| Parameter | Description |
| ----------------------- | ------------------------------------------------------------------ |
| `connection_timeout_ms` | Maximum time to wait for the TCP connection to be established. |
| `read_timeout_ms` | Maximum idle time between data packets while reading the response. |

```python
from box_sdk_gen import BoxClient, BoxDeveloperTokenAuth, NetworkSession, TimeoutConfig

auth = BoxDeveloperTokenAuth(token="DEVELOPER_TOKEN_GOES_HERE")
timeout_config = TimeoutConfig(
connection_timeout_ms=10000,
connection_timeout_ms=5000,
read_timeout_ms=30000,
)
network_session = NetworkSession(timeout_config=timeout_config)
Expand All @@ -211,9 +216,10 @@ client = BoxClient(auth=auth, network_session=network_session)
How timeout handling works:

- Timeout values are configured in milliseconds and converted to seconds internally for HTTP requests.
- If timeout config is not provided, the SDK uses default timeouts: `connection_timeout_ms=5000` (5 seconds) and `read_timeout_ms=60000` (60 seconds).
- If timeout config is not provided, the SDK uses default timeouts: `connection_timeout_ms=10000` (10 seconds) and `read_timeout_ms=60000` (60 seconds).
- When both `connection_timeout_ms` and `read_timeout_ms` are set, the SDK passes them as a `(connect, read)` tuple to the underlying `requests` library.
- When only one timeout is set, it applies as a single timeout value for the request.
- To disable all SDK timeouts, pass `TimeoutConfig(connection_timeout_ms=None, read_timeout_ms=None)` explicitly to `NetworkSession`.
- You can also disable only one timeout by setting one value to `None` (for example, `connection_timeout_ms=None` or `read_timeout_ms=None`). If you provide only the other value (for example, `read_timeout_ms=30000`) and leave one unspecified, the unspecified field remains `None` and that timeout stays disabled.
- Timeout failures are treated as network exceptions, and retry behavior is controlled by the configured retry strategy.
- Timeout applies to a single HTTP request attempt to the Box API (not the total time across all retries).
- If retries are exhausted, the SDK raises `BoxSDKError` with the underlying request exception.
14 changes: 7 additions & 7 deletions test/box_network_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ def network_session_mock():
def test_network_session_uses_default_timeout_config_values():
network_session = NetworkSession()

assert network_session.timeout_config.connection_timeout_ms == 5000
assert network_session.timeout_config.connection_timeout_ms == 10000
assert network_session.timeout_config.read_timeout_ms == 60000


Expand All @@ -191,7 +191,7 @@ def test_prepare_request_uses_default_network_session_timeouts(network_client):

api_request = network_client._prepare_request(options=options)

assert api_request.timeout == (5, 60)
assert api_request.timeout == (10, 60)


@pytest.fixture
Expand Down Expand Up @@ -339,7 +339,7 @@ def test_prepare_json_request(network_client, network_session_mock):
params={"param": "value"},
data='{"key": "value"}',
content_type="application/json",
timeout=(5, 60),
timeout=(10, 60),
)


Expand Down Expand Up @@ -727,7 +727,7 @@ def test_retrying_401_response_with_new_token_and_auth_provided(
data=None,
stream=True,
allow_redirects=True,
timeout=(5, 60),
timeout=(10, 60),
),
mock.call(
method="GET",
Expand All @@ -742,7 +742,7 @@ def test_retrying_401_response_with_new_token_and_auth_provided(
data=None,
stream=True,
allow_redirects=True,
timeout=(5, 60),
timeout=(10, 60),
),
],
)
Expand Down Expand Up @@ -782,7 +782,7 @@ def test_not_retrying_401_when_auth_not_provided(
data=None,
stream=True,
allow_redirects=True,
timeout=(5, 60),
timeout=(10, 60),
)


Expand Down Expand Up @@ -1244,5 +1244,5 @@ def test_disable_follow_redirects(
data=None,
stream=True,
allow_redirects=False,
timeout=(5, 60),
timeout=(10, 60),
)
Loading