Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
14 changes: 12 additions & 2 deletions lightly_studio/src/lightly_studio/core/file_outcome_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,13 @@ class FileOutcomeReport:
Attributes:
max_examples_per_outcome: Maximum number of example paths kept per
outcome.
label_overrides: Per-outcome display-label overrides used only by
`log_summary()`; any outcome absent from the dict falls back to
`outcome.value`. Defaults to empty (add-images behavior).
"""

max_examples_per_outcome: int = DEFAULT_MAX_EXAMPLES_PER_OUTCOME
label_overrides: dict[FileOutcome, str] = field(default_factory=dict)
Comment thread
JonasWurst marked this conversation as resolved.
Outdated
_counts: dict[FileOutcome, int] = field(
default_factory=lambda: dict.fromkeys(FileOutcome, 0),
init=False,
Expand Down Expand Up @@ -171,11 +175,17 @@ def raise_if_all_failed(self) -> None:
f"({n_missing} missing, {n_broken} broken)."
)

def _label(self, outcome: FileOutcome) -> str:
"""Return the display label for `outcome`, honoring `label_overrides`."""
return self.label_overrides.get(outcome, outcome.value)
Comment thread
JonasWurst marked this conversation as resolved.
Outdated

def log_summary(self) -> None:
"""Log a single end-of-run summary of counts and example paths."""
counts = ", ".join(f"{outcome.value}={self._counts[outcome]}" for outcome in FileOutcome)
counts = ", ".join(
f"{self._label(outcome)}={self._counts[outcome]}" for outcome in FileOutcome
)
logger.info(f"File outcomes: {counts}.")
for outcome in FileOutcome:
examples = self._example_paths[outcome]
if examples:
logger.info(f"Example {outcome.value} paths: {', '.join(examples)}.")
logger.info(f"Example {self._label(outcome)} paths: {', '.join(examples)}.")
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ def load_and_preprocess(filepath: str) -> torch.Tensor | None:
)

kept_indices_set = set(result.kept_indices)
report = FileOutcomeReport()
report = FileOutcomeReport(label_overrides={FileOutcome.ADDED: "embedded"})
for index, filepath in enumerate(filepaths):
outcome = FileOutcome.ADDED if index in kept_indices_set else FileOutcome.BROKEN
report.record(path=filepath, outcome=outcome)
Expand Down
38 changes: 38 additions & 0 deletions lightly_studio/tests/core/test_file_outcome_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,3 +140,41 @@ def test_log_summary(self, caplog: pytest.LogCaptureFixture) -> None:
assert "missing=1" in text
assert "a.jpg" in text
assert "b.jpg" in text
assert "Example added paths" in text

def test_log_summary__label_overrides(self, caplog: pytest.LogCaptureFixture) -> None:
report = FileOutcomeReport(label_overrides={FileOutcome.ADDED: "embedded"})
report.record(path="a.jpg", outcome=FileOutcome.ADDED)
report.record(path="b.jpg", outcome=FileOutcome.MISSING)

with caplog.at_level(logging.INFO):
report.log_summary()

text = caplog.text
# Overridden outcome uses the custom label.
assert "embedded=1" in text
assert "Example embedded paths" in text
assert "added=1" not in text
# Non-overridden outcomes still render their default labels.
assert "missing=1" in text

def test_log_summary__label_overrides_are_general(
self, caplog: pytest.LogCaptureFixture
) -> None:
report = FileOutcomeReport(
label_overrides={
FileOutcome.ADDED: "embedded",
FileOutcome.MISSING: "not_found",
}
)
report.record(path="a.jpg", outcome=FileOutcome.ADDED)
report.record(path="b.jpg", outcome=FileOutcome.MISSING)

with caplog.at_level(logging.INFO):
report.log_summary()

text = caplog.text
assert "embedded=1" in text
assert "not_found=1" in text
assert "Example not_found paths" in text
assert "missing=1" not in text
Loading