Skip to content

Commit 2c3e9fe

Browse files
v1r3nclaude
andcommitted
fix(http): guard private httpx attr, fix async comment, fix test mocks
- Wrap resp._request = None in try/except AttributeError for forward compat with future httpx versions - Fix async_rest.py comment: BoundSyncStream → BoundAsyncStream - Fix test_task_runner_coverage.py mocks: use mock_http_resp.data instead of dead mock_http_resp.resp (AuthorizationException now reads .data, not .resp.text) Follow-up to #395 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent c33f9b8 commit 2c3e9fe

3 files changed

Lines changed: 21 additions & 21 deletions

File tree

src/conductor/client/http/async_rest.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@ def __init__(self, resp):
1313
self.reason = getattr(resp, 'reason_phrase', '') or self._get_reason_phrase(resp.status_code)
1414
self.data = resp.text # eagerly read body
1515
self.headers = resp.headers
16-
# Break httpx Response <-> BoundSyncStream reference cycle (issue #395)
16+
# Break httpx Response <-> BoundAsyncStream reference cycle (issue #395)
1717
resp.stream = None
18-
resp._request = None
18+
try:
19+
resp._request = None
20+
except AttributeError:
21+
pass
1922

2023
def _get_reason_phrase(self, status_code):
2124
"""Get HTTP reason phrase from status code."""

src/conductor/client/http/rest.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ def __init__(self, resp):
1515
self.headers = resp.headers
1616
# Break httpx Response <-> BoundSyncStream reference cycle (issue #395)
1717
resp.stream = None
18-
resp._request = None
18+
try:
19+
resp._request = None
20+
except AttributeError:
21+
pass
1922

2023
def _get_reason_phrase(self, status_code):
2124
"""Get HTTP reason phrase from status code."""

tests/unit/automator/test_task_runner_coverage.py

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -316,15 +316,13 @@ def test_poll_task_auth_failure_with_invalid_token(self, mock_sleep):
316316
task_runner = TaskRunner(worker=worker)
317317

318318
# Create mock response with INVALID_TOKEN error
319-
mock_resp = Mock()
320-
mock_resp.text = '{"error": "INVALID_TOKEN"}'
321-
322319
mock_http_resp = Mock()
323-
mock_http_resp.resp = mock_resp
320+
mock_http_resp.data = '{"error": "INVALID_TOKEN"}'
321+
mock_http_resp.status = 401
322+
mock_http_resp.reason = 'Unauthorized'
323+
mock_http_resp.getheaders.return_value = {}
324324

325325
auth_exception = AuthorizationException(
326-
status=401,
327-
reason='Unauthorized',
328326
http_resp=mock_http_resp
329327
)
330328

@@ -342,15 +340,13 @@ def test_poll_task_auth_failure_without_invalid_token(self, mock_sleep):
342340
task_runner = TaskRunner(worker=worker)
343341

344342
# Create mock response with different error code
345-
mock_resp = Mock()
346-
mock_resp.text = '{"error": "FORBIDDEN"}'
347-
348343
mock_http_resp = Mock()
349-
mock_http_resp.resp = mock_resp
344+
mock_http_resp.data = '{"error": "FORBIDDEN"}'
345+
mock_http_resp.status = 403
346+
mock_http_resp.reason = 'Forbidden'
347+
mock_http_resp.getheaders.return_value = {}
350348

351349
auth_exception = AuthorizationException(
352-
status=403,
353-
reason='Forbidden',
354350
http_resp=mock_http_resp
355351
)
356352

@@ -420,15 +416,13 @@ def test_poll_task_with_metrics_on_auth_error(self):
420416
)
421417

422418
# Create mock response with INVALID_TOKEN error
423-
mock_resp = Mock()
424-
mock_resp.text = '{"error": "INVALID_TOKEN"}'
425-
426419
mock_http_resp = Mock()
427-
mock_http_resp.resp = mock_resp
420+
mock_http_resp.data = '{"error": "INVALID_TOKEN"}'
421+
mock_http_resp.status = 401
422+
mock_http_resp.reason = 'Unauthorized'
423+
mock_http_resp.getheaders.return_value = {}
428424

429425
auth_exception = AuthorizationException(
430-
status=401,
431-
reason='Unauthorized',
432426
http_resp=mock_http_resp
433427
)
434428

0 commit comments

Comments
 (0)