Skip to content

feat: add configurable request timeout support#49

Open
LegendEvent wants to merge 2 commits intodevfrom
feature/configurable-request-timeouts
Open

feat: add configurable request timeout support#49
LegendEvent wants to merge 2 commits intodevfrom
feature/configurable-request-timeouts

Conversation

@LegendEvent
Copy link
Owner

Summary

Adds configurable request timeout support to the Darktrace SDK with both client-level defaults and per-request overrides.

Changes

Core

  • Added TimeoutType alias and _resolve_timeout() helper to dt_utils.py
  • Added timeout parameter to DarktraceClient.__init__
  • Exported TimeoutType for type hints

Endpoints

  • Updated all 27 endpoint modules with timeout support
  • 75 requests.get/post/delete calls now support timeout parameter

Tests

  • Added tests/test_timeout.py with 11 comprehensive tests
  • All existing tests still pass (28 passed, 3 skipped)

Documentation

  • Updated README.md with timeout feature and usage examples
  • Updated docs/README.md with client options and examples

Usage

from darktrace import DarktraceClient

# Client-level timeout (applies to all requests)
client = DarktraceClient(
    host="https://your-instance.darktrace.com",
    public_token="...",
    private_token="...",
    timeout=30  # 30 seconds
)

# Per-request override for slow queries
results = client.advanced_search.search(query, timeout=600)  # 10 minutes

# Tuple format (connect_timeout, read_timeout)
results = client.advanced_search.search(query, timeout=(5, 300))

Backwards Compatibility

Fully backwards compatible - Default timeout is None (no timeout), matching previous behavior.

Test Results

tests/test_timeout.py: 11 passed
tests/test_devicesearch.py: 17 passed
Total: 28 passed, 3 skipped

- 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
Copilot AI review requested due to automatic review settings February 17, 2026 17:13
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 TimeoutType and a BaseEndpoint._resolve_timeout() helper; adds timeout to DarktraceClient and threads it through endpoint methods.
  • Updates all endpoint modules to pass timeout=... (and to honor client.verify_ssl for 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.

Comment on lines 18 to 22
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)
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_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.

Copilot uses AI. Check for mistakes.
Comment on lines 107 to 122
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

Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines +97 to +105
def __init__(
self,
host: str,
public_token: str,
private_token: str,
debug: bool = False,
verify_ssl: bool = True,
timeout: TimeoutType = None
) -> None:
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copilot uses AI. Check for mistakes.
@@ -1,10 +1,12 @@
from typing import TYPE_CHECKING, Union, Tuple
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Union and Tuple are imported but not used in this module. Please remove unused imports to avoid confusion and keep type-related imports minimal.

Suggested change
from typing import TYPE_CHECKING, Union, Tuple
from typing import TYPE_CHECKING

Copilot uses AI. Check for mistakes.
Comment on lines 434 to 448
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)"}
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copilot uses AI. Check for mistakes.
Comment on lines 19 to 20
response = requests.get(url, headers=headers, params=query_params, verify=self.client.verify_ssl)
```
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines 89 to 90
response = requests.get(url, headers=headers, params=sorted_params or params, verify=self.client.verify_ssl)
response.raise_for_status()
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
- Add _UNSET sentinel to distinguish 'not provided' from 'None'
- timeout=None now disables timeout (no timeout)
- timeout not provided uses client default
- Remove unused Union/Tuple imports from client.py
- Update tests and documentation

Addresses Copilot PR review comments #1 and #2
@LegendEvent LegendEvent changed the base branch from main to dev February 17, 2026 17:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments