Skip to content

Commit 5c2981d

Browse files
committed
minor cleanup
1 parent 24c6fe4 commit 5c2981d

4 files changed

Lines changed: 26 additions & 76 deletions

File tree

python/lib/sift_client/_tests/resources/test_test_results_log_file.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,6 @@ async def test_create_stamps_log_file(self, api):
9898
}
9999
result = await api.create(report_data, log_file=LOG)
100100
assert result._log_file == LOG
101-
# Confirm the resource forwards log_file to the low-level wrapper, i.e.
102-
# the value reaches the file-write branch (not just the returned entity).
103101
assert api._low_level_client.create_test_report.call_args.kwargs["log_file"] == LOG
104102

105103
@pytest.mark.asyncio
@@ -337,11 +335,8 @@ async def test_metadata_update_round_trips_through_log_file(self, real_api, tmp_
337335
"trial_number": 42.5,
338336
"is_dry_run": True,
339337
}
340-
await real_api.update(
341-
test_report=report,
342-
update={"metadata": metadata},
343-
log_file=report._log_file, # mirrors `log_file or self._log_file`
344-
)
338+
# No log_file kwarg — the resource layer must read it off the entity.
339+
await real_api.update(test_report=report, update={"metadata": metadata})
345340

346341
# Find the UpdateTestReport line and decode it the same way replay does.
347342
update_entries = [

python/lib/sift_client/_tests/sift_types/test_results.py

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -176,60 +176,12 @@ def test_update_test_report(self, mock_test_report, mock_client):
176176
)
177177
mock_update.assert_called_once_with(updated_report)
178178

179-
@pytest.mark.parametrize(
180-
"entity_fixture,resource_method,update_payload",
181-
[
182-
("mock_test_report", "update", {"status": TestStatus.FAILED}),
183-
("mock_test_step", "update_step", {"description": "x"}),
184-
("mock_test_measurement", "update_measurement", {"passed": False}),
185-
],
186-
)
187-
@pytest.mark.parametrize(
188-
"cached,kwarg,expected",
189-
[
190-
(None, None, None), # online: no cache, no kwarg -> None
191-
("/tmp/cached.jsonl", None, "/tmp/cached.jsonl"), # cache fallback (the fix)
192-
(None, "/tmp/kwarg.jsonl", "/tmp/kwarg.jsonl"), # explicit only
193-
("/tmp/cached.jsonl", "/tmp/kwarg.jsonl", "/tmp/kwarg.jsonl"), # kwarg wins
194-
],
195-
)
196-
def test_update_resolves_log_file(
197-
self,
198-
request,
199-
mock_client,
200-
entity_fixture,
201-
resource_method,
202-
update_payload,
203-
cached,
204-
kwarg,
205-
expected,
206-
):
207-
"""Entity .update() forwards `log_file or self._log_file` to the resource.
208-
209-
Covers all four (cached, kwarg) combinations across all three entity types.
210-
"""
211-
entity = request.getfixturevalue(entity_fixture)
212-
if cached is not None:
213-
entity.__dict__["_log_file"] = cached
214-
mock_method = getattr(mock_client.test_results, resource_method)
215-
mock_method.return_value = MagicMock()
216-
entity._update = MagicMock()
217-
218-
if kwarg is not None:
219-
entity.update(update_payload, log_file=kwarg)
220-
else:
221-
entity.update(update_payload)
222-
223-
assert mock_method.call_args.kwargs["log_file"] == expected
224-
225179
def test_update_preserves_cached_log_file(self, mock_test_report, mock_client):
226180
"""After .update() returns, the cached _log_file survives — BaseType._update()
227181
only copies model_fields, and private attrs are excluded.
228182
"""
229183
mock_test_report.__dict__["_log_file"] = "/tmp/cached.jsonl"
230184

231-
# The returned entity from the resource layer carries its own _log_file
232-
# via _stamp_log_file. Real _update() should not clobber self._log_file.
233185
updated = TestReport(
234186
id_=mock_test_report.id_,
235187
status=TestStatus.FAILED,

python/lib/sift_client/resources/test_results.py

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,14 @@ def __init__(self, sift_client: SiftClient):
4747
self._low_level_client = TestResultsLowLevelClient(grpc_client=self.client.grpc_client)
4848
self._upload_client = UploadLowLevelClient(rest_client=self.client.rest_client)
4949

50-
@staticmethod
51-
def _associate_log_file(instance, log_file: str | Path | None):
52-
# Mirror BaseType._apply_client_to_instance: bypass frozen by writing to
53-
# __dict__ directly.
50+
def _finalize(self, instance, log_file: str | Path | None):
51+
"""Attach the client and stamp the log file on a returned entity.
52+
53+
Bypasses the frozen-model guard the same way `_apply_client_to_instance`
54+
does. Read paths skip this and call `_apply_client_to_instance` directly
55+
so fetched entities don't carry a log file they didn't originate from.
56+
"""
57+
self._apply_client_to_instance(instance)
5458
instance.__dict__["_log_file"] = log_file
5559
return instance
5660

@@ -93,7 +97,7 @@ async def create(
9397
test_report=test_report,
9498
log_file=log_file,
9599
)
96-
return self._associate_log_file(self._apply_client_to_instance(created_report), log_file)
100+
return self._finalize(created_report, log_file)
97101

98102
async def get(self, *, test_report_id: str) -> TestReport:
99103
"""Get a TestReport.
@@ -269,9 +273,7 @@ async def update(
269273
updated_test_report = await self._low_level_client.update_test_report(
270274
update, log_file=log_file, existing=existing
271275
)
272-
return self._associate_log_file(
273-
self._apply_client_to_instance(updated_test_report), log_file
274-
)
276+
return self._finalize(updated_test_report, log_file)
275277

276278
async def archive(self, *, test_report: str | TestReport) -> TestReport:
277279
"""Archive a test report.
@@ -319,7 +321,7 @@ async def create_step(
319321
test_step_result = await self._low_level_client.create_test_step(
320322
test_step, log_file=log_file
321323
)
322-
return self._associate_log_file(self._apply_client_to_instance(test_step_result), log_file)
324+
return self._finalize(test_step_result, log_file)
323325

324326
async def list_steps(
325327
self,
@@ -450,7 +452,7 @@ async def update_step(
450452
updated_test_step = await self._low_level_client.update_test_step(
451453
update, log_file=log_file, existing=existing
452454
)
453-
return self._associate_log_file(self._apply_client_to_instance(updated_test_step), log_file)
455+
return self._finalize(updated_test_step, log_file)
454456

455457
async def delete_step(self, *, test_step: str | TestStep) -> None:
456458
"""Delete a test step.
@@ -484,9 +486,7 @@ async def create_measurement(
484486
test_measurement_result = await self._low_level_client.create_test_measurement(
485487
test_measurement, log_file=log_file
486488
)
487-
measurement = self._associate_log_file(
488-
self._apply_client_to_instance(test_measurement_result), log_file
489-
)
489+
measurement = self._finalize(test_measurement_result, log_file)
490490
if update_step and log_file is None:
491491
step = await self.get_step(test_step=test_measurement_result.test_step_id)
492492
if step.status == TestStatus.PASSED and not measurement.passed:
@@ -623,9 +623,7 @@ async def update_measurement(
623623
updated_test_measurement = await self._low_level_client.update_test_measurement(
624624
update, log_file=log_file, existing=test_measurement
625625
)
626-
updated_test_measurement = self._associate_log_file(
627-
self._apply_client_to_instance(updated_test_measurement), log_file
628-
)
626+
updated_test_measurement = self._finalize(updated_test_measurement, log_file)
629627
if update_step and log_file is None and update.passed is not None and not update.passed:
630628
step = await self.get_step(test_step=updated_test_measurement.test_step_id)
631629
if step.status == TestStatus.PASSED:

python/lib/sift_client/sift_types/test_report.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,11 @@ def update(
204204
update: TestStepUpdate | dict,
205205
log_file: str | Path | None = None,
206206
) -> TestStep:
207-
"""Update the TestStep."""
208-
log_file = log_file if log_file is not None else self._log_file
207+
"""Update the TestStep.
208+
209+
If `log_file` is omitted, the resource layer falls back to the value
210+
cached on `self` from the create call (offline/logging mode).
211+
"""
209212
updated_test_step = self.client.test_results.update_step(
210213
test_step=self, update=update, log_file=log_file
211214
)
@@ -431,7 +434,6 @@ def update(
431434
Returns:
432435
The updated TestMeasurement.
433436
"""
434-
log_file = log_file if log_file is not None else self._log_file
435437
updated_test_measurement = self.client.test_results.update_measurement(
436438
test_measurement=self, update=update, update_step=update_step, log_file=log_file
437439
)
@@ -613,8 +615,11 @@ def update(
613615
update: TestReportUpdate | dict,
614616
log_file: str | Path | None = None,
615617
) -> TestReport:
616-
"""Update the TestReport."""
617-
log_file = log_file if log_file is not None else self._log_file
618+
"""Update the TestReport.
619+
620+
If `log_file` is omitted, the resource layer falls back to the value
621+
cached on `self` from the create call (offline/logging mode).
622+
"""
618623
updated_test_report = self.client.test_results.update(
619624
test_report=self, update=update, log_file=log_file
620625
)

0 commit comments

Comments
 (0)