feat: add configurable request timeout support#49
Conversation
- Add timeout parameter to DarktraceClient (default: None for backwards compatibility) - Add per-request timeout override to all endpoint methods - Support tuple format: timeout=(connect_timeout, read_timeout) - Add TimeoutType export for type hints - Add comprehensive test suite (11 tests) - Update README and docs with timeout documentation This enables users to: - Set client-wide timeout: DarktraceClient(timeout=30) - Override per-request: client.advanced_search.search(query, timeout=600) - Use granular timeouts: timeout=(5, 30) for connect/read
There was a problem hiding this comment.
Pull request overview
Adds request timeout configurability across the Darktrace SDK (client default + per-call override) by plumbing a timeout parameter through all endpoint methods and standardizing how the value is resolved/passed into requests.
Changes:
- Introduces
TimeoutTypeand aBaseEndpoint._resolve_timeout()helper; addstimeouttoDarktraceClientand threads it through endpoint methods. - Updates all endpoint modules to pass
timeout=...(and to honorclient.verify_sslfor TLS verification). - Adds a dedicated timeout test suite and updates docs/examples to reflect the new configuration options.
Reviewed changes
Copilot reviewed 36 out of 36 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
darktrace/dt_utils.py |
Adds TimeoutType alias and _resolve_timeout() helper used by all endpoints. |
darktrace/client.py |
Adds verify_ssl and timeout to client initialization and stores them on the client. |
darktrace/__init__.py |
Exports TimeoutType at package level for type hints. |
darktrace/dt_advanced_search.py |
Adds per-call timeout support for advanced search endpoints. |
darktrace/dt_analyst.py |
Adds timeout support to AI Analyst endpoints. |
darktrace/dt_antigena.py |
Adds timeout support to Antigena endpoints; also adds an approve_action() no-op method. |
darktrace/dt_breaches.py |
Adds timeout support and ensures list-parameter helper methods forward it. |
darktrace/dt_components.py |
Adds timeout to components GET request. |
darktrace/dt_cves.py |
Adds timeout to CVEs GET request. |
darktrace/dt_details.py |
Adds timeout to details GET request. |
darktrace/dt_deviceinfo.py |
Adds timeout to device info GET request. |
darktrace/dt_devices.py |
Adds timeout to devices GET and update POST requests. |
darktrace/dt_devicesearch.py |
Adds timeout to devicesearch GET and forwards it through helper methods. |
darktrace/dt_devicesummary.py |
Adds timeout to devicesummary GET request. |
darktrace/dt_email.py |
Adds timeout across Darktrace Email API endpoints. |
darktrace/dt_endpointdetails.py |
Adds timeout to endpointdetails GET request. |
darktrace/dt_enums.py |
Adds timeout to enums GET request. |
darktrace/dt_filtertypes.py |
Adds timeout to filtertypes GET request. |
darktrace/dt_intelfeed.py |
Adds timeout to intelfeed GET/POST requests. |
darktrace/dt_mbcomments.py |
Adds timeout to mbcomments GET/POST requests. |
darktrace/dt_metricdata.py |
Adds timeout to metricdata GET request. |
darktrace/dt_metrics.py |
Adds timeout to metrics GET request. |
darktrace/dt_models.py |
Adds timeout to models GET request. |
darktrace/dt_network.py |
Adds timeout to network GET request. |
darktrace/dt_pcaps.py |
Adds timeout to pcaps GET/POST requests. |
darktrace/dt_similardevices.py |
Adds timeout to similardevices GET request. |
darktrace/dt_status.py |
Adds timeout to status GET request. |
darktrace/dt_subnets.py |
Adds timeout to subnets GET/POST requests. |
darktrace/dt_summarystatistics.py |
Adds timeout to summarystatistics GET request. |
darktrace/dt_tags.py |
Adds timeout across tags GET/POST/DELETE requests. |
tests/test_timeout.py |
New tests verifying client default and per-call timeout propagation. |
README.md |
Documents timeout usage and SSL verification defaults; updates release notes section. |
docs/README.md |
Adds client options table and examples for SSL verification + timeouts. |
docs/authentication_fix.md |
Updates request examples to reference verify_ssl. |
examples/tor_exit_nodes.py |
Removes urllib3 warning suppression; adds note on verify_ssl=False for dev. |
examples/threat_intelligence.py |
Removes urllib3 warning suppression. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
darktrace/dt_utils.py
Outdated
| def _resolve_timeout(self, timeout: TimeoutType) -> TimeoutType: | ||
| """Resolve timeout value, using client default if not specified.""" | ||
| if timeout is not None: | ||
| return timeout | ||
| return getattr(self.client, 'timeout', None) |
There was a problem hiding this comment.
_resolve_timeout() treats timeout=None as "use client default". Since TimeoutType includes None to mean "no timeout", this makes it impossible to override a client-level default timeout to "no timeout" on a single request, and it conflicts with the README/docs that describe timeout=None as disabling timeouts. Consider using a sentinel default (e.g., timeout=_UNSET) so callers can explicitly pass None to disable the timeout while still supporting an unspecified value that falls back to client.timeout.
tests/test_timeout.py
Outdated
| def test_per_request_none_uses_client_default(self, mock_response): | ||
| """Per-request None should use client default.""" | ||
| client = DarktraceClient( | ||
| host="https://test.darktrace.com", | ||
| public_token="test_public", | ||
| private_token="test_private", | ||
| timeout=30.0, | ||
| ) | ||
|
|
||
| with patch("darktrace.dt_devices.requests.get", return_value=mock_response) as mock_get: | ||
| # Explicitly passing None should use client default | ||
| client.devices.get(timeout=None) | ||
|
|
||
| call_kwargs = mock_get.call_args[1] | ||
| assert call_kwargs.get("timeout") == 30.0 | ||
|
|
There was a problem hiding this comment.
This test codifies the behavior that explicitly passing timeout=None uses the client default timeout. That makes it impossible for callers to override a client default timeout to "no timeout" per request, and it contradicts the documented meaning of timeout=None. If you change the API to use a sentinel for "not provided", update this test to assert that passing None disables timeouts for that call.
| def __init__( | ||
| self, | ||
| host: str, | ||
| public_token: str, | ||
| private_token: str, | ||
| debug: bool = False, | ||
| verify_ssl: bool = True, | ||
| timeout: TimeoutType = None | ||
| ) -> None: |
There was a problem hiding this comment.
The PR description states the change is fully backwards compatible and focused on timeouts, but verify_ssl is added here with a default of True, which changes behavior for users relying on the previous default (notably self-signed cert setups). Please update the PR description/release notes to call out this behavioral change explicitly (or consider deferring it to a separate PR).
darktrace/client.py
Outdated
| @@ -1,10 +1,12 @@ | |||
| from typing import TYPE_CHECKING, Union, Tuple | |||
There was a problem hiding this comment.
Union and Tuple are imported but not used in this module. Please remove unused imports to avoid confusion and keep type-related imports minimal.
| from typing import TYPE_CHECKING, Union, Tuple | |
| from typing import TYPE_CHECKING |
| def approve_action(self, codeid: int) -> dict: | ||
| """ | ||
| Approve a pending Darktrace RESPOND action (backwards compatibility, no-op). | ||
|
|
||
| This method is retained for backwards compatibility only. In modern Darktrace | ||
| versions, the approve/decline workflow has been replaced by direct action | ||
| management methods. This method is a no-op that returns a success response. | ||
|
|
||
| Args: | ||
| codeid (int): Unique numeric identifier of a RESPOND action (ignored). | ||
|
|
||
| Returns: | ||
| dict: A dummy success response for backwards compatibility. | ||
| """ | ||
| return {"success": True, "message": "Action approved (no-op for backwards compatibility)"} |
There was a problem hiding this comment.
approve_action() is introduced as a new public method but it’s not mentioned in the PR description (which is focused on timeouts). If this is needed for backwards compatibility, please add a short note in the PR description/changelog and consider adding a regression test to lock in the intended no-op behavior (or move this change to a separate PR to keep scope tight).
| response = requests.get(url, headers=headers, params=query_params, verify=self.client.verify_ssl) | ||
| ``` |
There was a problem hiding this comment.
The documentation snippet uses verify=self.client.verify_ssl, but this section isn’t inside a class/method context where self is defined. Adjust the example to use an in-scope variable (e.g., client.verify_ssl or a literal verify=True/False) so the snippet is runnable and unambiguous.
| response = requests.get(url, headers=headers, params=sorted_params or params, verify=self.client.verify_ssl) | ||
| response.raise_for_status() |
There was a problem hiding this comment.
Same issue as earlier in the doc: this example uses self.client.verify_ssl in a standalone snippet. Update it to use an in-scope variable name (e.g., client.verify_ssl) or keep it as verify=True/False for clarity.
Summary
Adds configurable request timeout support to the Darktrace SDK with both client-level defaults and per-request overrides.
Changes
Core
TimeoutTypealias and_resolve_timeout()helper todt_utils.pytimeoutparameter toDarktraceClient.__init__TimeoutTypefor type hintsEndpoints
Tests
tests/test_timeout.pywith 11 comprehensive testsDocumentation
Usage
Backwards Compatibility
✅ Fully backwards compatible - Default timeout is
None(no timeout), matching previous behavior.Test Results