Files
wehub-resource-sync 9194ef5abd
Docs/Test Workflow / Test docs build (push) Failing after 0s
Check links & references / links-check (push) Failing after 1s
Pytest/Test Workflow / Import Test and Pytest Run (ubuntu-latest, 3.10) (push) Failing after 0s
Pytest/Test Workflow / Import Test and Pytest Run (ubuntu-latest, 3.11) (push) Failing after 0s
PR Conflict Labeler / main (push) Failing after 2s
Pytest/Test Workflow / Import Test and Pytest Run (ubuntu-latest, 3.12) (push) Failing after 2s
Pytest/Test Workflow / Import Test and Pytest Run (ubuntu-latest, 3.13) (push) Failing after 0s
Pytest/Test Workflow / Build this Package (push) Failing after 5s
Pytest/Test Workflow / Import Test and Pytest Run (macos-latest, 3.10) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (macos-latest, 3.11) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (macos-latest, 3.12) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (macos-latest, 3.13) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (windows-latest, 3.10) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (windows-latest, 3.11) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (windows-latest, 3.12) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (windows-latest, 3.13) (push) Has been cancelled
Pytest/Test Workflow / testing-guardian (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:06:10 +08:00

143 lines
4.7 KiB
Python

from __future__ import annotations
from contextlib import ExitStack as DoesNotRaise
import numpy as np
import pytest
from supervision.classification.core import Classifications
class _MockTensor:
"""Minimal tensor double that supports the tensor chain used by adapters."""
def __init__(self, value: np.ndarray) -> None:
self.value = value
def softmax(self, dim: int) -> _MockTensor:
"""Return a tensor double with softmax applied along the requested axis."""
if self.value.shape[dim] == 0:
return _MockTensor(self.value)
exp = np.exp(self.value - np.max(self.value, axis=dim, keepdims=True))
return _MockTensor(exp / np.sum(exp, axis=dim, keepdims=True))
def cpu(self) -> _MockTensor:
"""Return the tensor double for chained CPU conversion calls."""
return self
def detach(self) -> _MockTensor:
"""Return the tensor double for chained graph-detach calls."""
return self
def numpy(self) -> np.ndarray:
"""Return the wrapped NumPy array."""
return self.value
@pytest.mark.parametrize(
("class_id", "confidence", "k", "expected_result", "exception"),
[
(
np.array([0, 1, 2, 3, 4]),
np.array([0.1, 0.2, 0.9, 0.4, 0.5]),
5,
(np.array([2, 4, 3, 1, 0]), np.array([0.9, 0.5, 0.4, 0.2, 0.1])),
DoesNotRaise(),
), # class_id with 5 numbers and 5 confidences
(
np.array([5, 1, 2, 3, 4]),
np.array([0.1, 0.2, 0.9, 0.4, 0.5]),
1,
(np.array([2]), np.array([0.9])),
DoesNotRaise(),
), # class_id with 5 numbers and 5 confidences, retrieve where k = 1
(
np.array([4, 1, 2, 3, 6, 5]),
np.array([0.8, 0.2, 0.9, 0.4, 0.5, 0.1]),
2,
(np.array([2, 4]), np.array([0.9, 0.8])),
DoesNotRaise(),
), # class_id with 5 numbers and 5 confidences, retrieve where k = 3
(
np.array([0, 1, 2, 3, 4]),
np.array([]),
5,
None,
pytest.raises(ValueError, match=r"confidence must be 1d np\.ndarray"),
), # class_id with 5 numbers and 0 confidences
(
[0, 1, 2, 3, 4],
[0.1, 0.2, 0.3, 0.4],
5,
None,
pytest.raises(ValueError, match="\\(n, \\) shape"),
), # class_id with 5 numbers and 4 confidences
],
)
def test_top_k(
class_id: np.ndarray,
confidence: np.ndarray | None,
k: int,
expected_result: tuple[np.ndarray, np.ndarray] | None,
exception: Exception,
) -> None:
"""Retrieves requested top-k values or raises for malformed confidence input."""
with exception:
result = Classifications(
class_id=np.array(class_id), confidence=np.array(confidence)
).get_top_k(k)
assert np.array_equal(result[0], expected_result[0])
assert np.array_equal(result[1], expected_result[1])
def test_from_clip_empty_output_dtypes() -> None:
"""Empty CLIP logits produce typed empty classification arrays."""
result = Classifications.from_clip(_MockTensor(np.empty((1, 0), dtype=np.float32)))
assert result.class_id.dtype == np.int_
assert result.confidence is not None
assert result.confidence.dtype == np.float32
def test_from_timm_empty_output_dtypes() -> None:
"""Empty timm logits produce typed empty classification arrays."""
result = Classifications.from_timm(_MockTensor(np.empty((1, 0), dtype=np.float32)))
assert result.class_id.dtype == np.int_
assert result.confidence is not None
assert result.confidence.dtype == np.float32
def test_from_timm_softmaxes_logits() -> None:
"""Timm logits are converted to normalized confidence scores."""
logits = np.array([[0.0, 1.0, 2.0]], dtype=np.float32)
result = Classifications.from_timm(_MockTensor(logits))
assert result.confidence is not None
assert np.allclose(
result.confidence, _MockTensor(logits).softmax(dim=-1).numpy()[0]
)
assert np.isclose(np.sum(result.confidence), 1.0)
def test_classifications_compare_numpy_fields_by_value() -> None:
"""Classifications equality handles NumPy arrays and confidence values."""
left = Classifications(
class_id=np.array([0, 1], dtype=np.int_),
confidence=np.array([0.25, 0.75], dtype=np.float32),
)
right = Classifications(
class_id=np.array([0, 1], dtype=np.int_),
confidence=np.array([0.25, 0.75], dtype=np.float32),
)
different = Classifications(
class_id=np.array([0, 1], dtype=np.int_),
confidence=np.array([0.25, 0.5], dtype=np.float32),
)
assert left == right
assert left != different