Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
5 changes: 5 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@
- `/docs/testing.md` documents test tiers, CI expectations, smoke tests, nightly
tests, and manual validation policy.
- `/docs/adr/` documents architecture decisions and design contracts.
- The only showcase/sample image is `libreyolo/assets/guggenheim-bilbao.jpg`
(`libreyolo.SAMPLE_IMAGE`). Never use or reintroduce `parkour.jpg` in
user-facing material. A test-only copy lives in `tests/data/parkour.jpg`
for parity and golden tests; `tests/unit/test_no_parkour_sample.py`
enforces this.

## README policy

Expand Down
2 changes: 1 addition & 1 deletion libreyolo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@
"Identities",
)

SAMPLE_IMAGE = str(_Path(__file__).parent / "assets" / "parkour.jpg")
SAMPLE_IMAGE = str(_Path(__file__).parent / "assets" / "guggenheim-bilbao.jpg")

try:
__version__ = version("libreyolo")
Expand Down
Binary file removed libreyolo/assets/parkour_result.jpg
Binary file not shown.
2 changes: 1 addition & 1 deletion libreyolo/cli/commands/predict.py
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,7 @@ def predict_cmd(
}
result_list.append(result_data)
# Human summary line:
# image 1/3 parkour.jpg: 640x480 3 persons, 2 skateboards, 45.2ms
# image 1/1 guggenheim-bilbao.jpg: 1536x1194 1 person, 59.5ms avg
counts_str = ", ".join(
f"{v} {k}{'s' if v > 1 else ''}" for k, v in class_counts.items()
)
Expand Down
2 changes: 1 addition & 1 deletion scripts/run_sample_predict.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from pathlib import Path

SAMPLE_IMAGES = {
"parkour": Path(__file__).resolve().parents[1] / "libreyolo" / "assets" / "parkour.jpg",
"guggenheim-bilbao": Path(__file__).resolve().parents[1] / "libreyolo" / "assets" / "guggenheim-bilbao.jpg",
}


Expand Down
File renamed without changes
4 changes: 2 additions & 2 deletions tests/data/rfdetr_keypoint_parkour_golden.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"description": "RF-DETR GroupPose keypoint oracle golden for libreyolo/assets/parkour.jpg (852x1280 HxW). Generated from official_kp_parity.pt blob[final]. conf=0.3, 4 person detections. boxes xyxy and kp_xy in source-image pixels; kp_confidence is findable.sigmoid().",
"source_image": "libreyolo/assets/parkour.jpg",
"description": "RF-DETR GroupPose keypoint oracle golden for tests/data/parkour.jpg (852x1280 HxW). Generated from official_kp_parity.pt blob[final]. conf=0.3, 4 person detections. boxes xyxy and kp_xy in source-image pixels; kp_confidence is findable.sigmoid().",
"source_image": "tests/data/parkour.jpg",
"source_shape_hw": [
852,
1280
Expand Down
26 changes: 13 additions & 13 deletions tests/e2e/cli/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ def app(self):

def test_predict_basic(self, app):
result = runner.invoke(
app, ["predict", "source=libreyolo/assets/parkour.jpg", "model=yolox-s"]
app, ["predict", "source=tests/data/parkour.jpg", "model=yolox-s"]
)
assert result.exit_code == 0
assert "person" in result.output
Expand All @@ -188,7 +188,7 @@ def test_predict_json(self, app):
app,
[
"predict",
"source=libreyolo/assets/parkour.jpg",
"source=tests/data/parkour.jpg",
"model=yolox-s",
"--json",
],
Expand All @@ -205,7 +205,7 @@ def test_predict_with_conf(self, app):
app,
[
"predict",
"source=libreyolo/assets/parkour.jpg",
"source=tests/data/parkour.jpg",
"model=yolox-s",
"conf=0.9",
"--json",
Expand All @@ -222,7 +222,7 @@ def test_predict_key_value_syntax(self, app):
app,
[
"predict",
"source=libreyolo/assets/parkour.jpg",
"source=tests/data/parkour.jpg",
"model=yolox-s",
"conf=0.5",
],
Expand All @@ -237,7 +237,7 @@ def test_predict_standard_syntax(self, app):
[
"predict",
"--source",
"libreyolo/assets/parkour.jpg",
"tests/data/parkour.jpg",
"--model",
"yolox-s",
"--conf",
Expand All @@ -253,7 +253,7 @@ def test_predict_mixed_syntax(self, app):
app,
[
"predict",
"source=libreyolo/assets/parkour.jpg",
"source=tests/data/parkour.jpg",
"--model",
"yolox-s",
"conf=0.5",
Expand All @@ -270,7 +270,7 @@ def test_predict_bare_bool_flags(self, app):
app,
[
"predict",
"source=libreyolo/assets/parkour.jpg",
"source=tests/data/parkour.jpg",
"model=yolox-s",
"half",
"save",
Expand All @@ -287,7 +287,7 @@ def test_predict_save(self, app):
app,
[
"predict",
"source=libreyolo/assets/parkour.jpg",
"source=tests/data/parkour.jpg",
"model=yolox-s",
"save",
"--json",
Expand All @@ -303,7 +303,7 @@ def test_predict_local_weights(self, app):
app,
[
"predict",
"source=libreyolo/assets/parkour.jpg",
"source=tests/data/parkour.jpg",
"model=weights/LibreYOLOXs.pt",
"--json",
],
Expand All @@ -320,7 +320,7 @@ def test_predict_reports_effective_imgsz(self, app):
app,
[
"predict",
"source=libreyolo/assets/parkour.jpg",
"source=tests/data/parkour.jpg",
"model=weights/LibreYOLOXs.pt",
"imgsz=320",
"--json",
Expand Down Expand Up @@ -367,7 +367,7 @@ def test_detect_task_prefix(self, app, monkeypatch):
"libreyolo",
"detect",
"predict",
"source=libreyolo/assets/parkour.jpg",
"source=tests/data/parkour.jpg",
"model=yolox-s",
"--json",
],
Expand Down Expand Up @@ -505,7 +505,7 @@ def test_predict_yolo9(self, app):
app,
[
"predict",
"source=libreyolo/assets/parkour.jpg",
"source=tests/data/parkour.jpg",
"model=yolo9-t",
"--json",
],
Expand All @@ -525,7 +525,7 @@ def test_predict_rfdetr(self, app):
app,
[
"predict",
"source=libreyolo/assets/parkour.jpg",
"source=tests/data/parkour.jpg",
"model=rfdetr-n",
"--json",
],
Expand Down
8 changes: 8 additions & 0 deletions tests/e2e/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,14 @@ def sample_image():
return SAMPLE_IMAGE


@pytest.fixture(scope="session")
def parkour_fixture_image():
"""Test-only parity image whose exact pixels some numeric checks rely on."""
from tests.fixture_images import PARKOUR_FIXTURE

return PARKOUR_FIXTURE


@pytest.fixture(scope="function")
def temp_export_dir(tmp_path):
"""Create a temporary directory for export artifacts."""
Expand Down
2 changes: 1 addition & 1 deletion tests/e2e/test_deeplabv3_exports.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def test_official_checkpoint_export_runtime_parity(tmp_path, size, format_name):

device = "cuda" if format_name == "tensorrt" else "cpu"
native = LibreYOLO(str(checkpoint), device=device)
image = Path("libreyolo/assets/parkour.jpg")
image = Path("tests/data/parkour.jpg")
input_tensor, _, _, _ = native._preprocess(image, input_size=520)
with torch.inference_mode():
expected_raw = native.model(input_tensor.to(device)).detach().cpu().numpy()
Expand Down
2 changes: 1 addition & 1 deletion tests/e2e/test_deformable_detr_onnx.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ def test_official_checkpoint_onnx_predict_parity(
model.model.eval()
del state_dict

image = Path("libreyolo/assets/parkour.jpg")
image = Path("tests/data/parkour.jpg")
input_tensor, _, _, _ = model._preprocess(image, input_size=800)
trace_device = "cpu" if size == "r50twostage" else device
trace_tensor = input_tensor.to(trace_device)
Expand Down
2 changes: 1 addition & 1 deletion tests/e2e/test_dekr_pose.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
pytestmark = [pytest.mark.e2e, pytest.mark.dekr]

REPO_ROOT = Path(__file__).resolve().parents[2]
IMAGE = REPO_ROOT / "libreyolo" / "assets" / "parkour.jpg"
IMAGE = REPO_ROOT / "tests" / "data" / "parkour.jpg"
FAMILY, SIZE, WEIGHTS = DEKR_POSE_MODELS[0]


Expand Down
2 changes: 1 addition & 1 deletion tests/e2e/test_dinodetr_onnx.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def test_official_checkpoint_onnx_predict_parity(
# lowering this CUDA graph. CPU traces the same operators and is portable.
device = "cpu"
model = LibreDINODETR(str(source), size=size, device=device)
image = Path("libreyolo/assets/parkour.jpg")
image = Path("tests/data/parkour.jpg")
input_tensor, _, _, _ = model._preprocess(image, input_size=export_size)
exporter = OnnxExporter(model)
with (
Expand Down
6 changes: 3 additions & 3 deletions tests/e2e/test_embed_smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def test_clip_embed_text_gallery_and_batch_smoke(tmp_path):
result = model.predict(SAMPLE_IMAGE)
image_vector = result.embeddings.data
text_vectors = model.embed_text(
["people doing parkour outdoors", "a close-up photograph of a dog"]
["a person doing a flip in front of a museum", "a close-up photograph of a dog"]
)

assert result.boxes is None
Expand All @@ -43,7 +43,7 @@ def test_clip_embed_text_gallery_and_batch_smoke(tmp_path):
assert "embedding" in result.summary(embeddings=True)[0]

gallery = Gallery(model)
assert gallery.enroll("parkour", SAMPLE_IMAGE) == 1
assert gallery.enroll("guggenheim", SAMPLE_IMAGE) == 1
gallery_path = tmp_path / "images.gallery.npz"
gallery.save(gallery_path)
restored = Gallery.load(gallery_path, model=model)
Expand All @@ -53,4 +53,4 @@ def test_clip_embed_text_gallery_and_batch_smoke(tmp_path):
gallery=restored,
threshold=0.99,
)
assert identified.identities.name == ["parkour"]
assert identified.identities.name == ["guggenheim"]
2 changes: 1 addition & 1 deletion tests/e2e/test_matte_birefnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

REPO = Path(__file__).resolve().parents[2]
FIXT = REPO / "tests" / "fixtures" / "matte8"
_SAMPLE = REPO / "libreyolo" / "assets" / "parkour.jpg"
_SAMPLE = REPO / "tests" / "data" / "parkour.jpg"
_LOCAL_T = REPO / "weights" / "LibreBiRefNett-matte.pt"


Expand Down
2 changes: 1 addition & 1 deletion tests/e2e/test_ncnn_round18.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ def _match_detection_rows(expected_data, actual_data):

def _assert_predict_parity(case, model, backend) -> None:
if case.weights is not None:
source = str(Path("libreyolo/assets/parkour.jpg"))
source = str(Path("tests/data/parkour.jpg"))
confidence = 0.05
else:
source = np.random.default_rng(118).integers(
Expand Down
24 changes: 12 additions & 12 deletions tests/e2e/test_ppyoloe_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def _assert_public_parity(model, backend, image, box_atol, score_atol):


@pytest.mark.torchscript
def test_torchscript_is_bit_exact(tmp_path, sample_image):
def test_torchscript_is_bit_exact(tmp_path, parkour_fixture_image):
from libreyolo import LibreYOLO

weights = require_test_weights(WEIGHTS, expected_family="ppyoloe")
Expand All @@ -129,12 +129,12 @@ def test_torchscript_is_bit_exact(tmp_path, sample_image):
assert backend.task == "detect"
assert backend.imgsz == IMGSZ

_assert_raw_parity(model, backend, sample_image, box_atol=0.0, score_atol=0.0)
_assert_public_parity(model, backend, sample_image, box_atol=0.0, score_atol=0.0)
_assert_raw_parity(model, backend, parkour_fixture_image, box_atol=0.0, score_atol=0.0)
_assert_public_parity(model, backend, parkour_fixture_image, box_atol=0.0, score_atol=0.0)


@pytest.mark.onnx
def test_onnx_raw_contract_and_parity(tmp_path, sample_image):
def test_onnx_raw_contract_and_parity(tmp_path, parkour_fixture_image):
import onnx

from libreyolo import LibreYOLO
Expand All @@ -153,8 +153,8 @@ def test_onnx_raw_contract_and_parity(tmp_path, sample_image):
assert backend.imgsz == IMGSZ
assert backend.names[0] == "person"

_assert_raw_parity(model, backend, sample_image, box_atol=1e-2, score_atol=1e-5)
_assert_public_parity(model, backend, sample_image, box_atol=1e-2, score_atol=1e-5)
_assert_raw_parity(model, backend, parkour_fixture_image, box_atol=1e-2, score_atol=1e-5)
_assert_public_parity(model, backend, parkour_fixture_image, box_atol=1e-2, score_atol=1e-5)


@pytest.mark.onnx
Expand All @@ -171,7 +171,7 @@ def test_onnx_rejects_a_shape_it_was_not_exported_for(tmp_path):


@pytest.mark.openvino
def test_openvino_parity(tmp_path, sample_image):
def test_openvino_parity(tmp_path, parkour_fixture_image):
pytest.importorskip("openvino")
from libreyolo import LibreYOLO

Expand All @@ -181,12 +181,12 @@ def test_openvino_parity(tmp_path, sample_image):
backend = LibreYOLO(str(artifact), device="cpu")

assert backend.model_family == "ppyoloe"
_assert_raw_parity(model, backend, sample_image, box_atol=5.0, score_atol=1e-2)
_assert_public_parity(model, backend, sample_image, box_atol=0.5, score_atol=1e-3)
_assert_raw_parity(model, backend, parkour_fixture_image, box_atol=5.0, score_atol=1e-2)
_assert_public_parity(model, backend, parkour_fixture_image, box_atol=0.5, score_atol=1e-3)


@pytest.mark.tensorrt
def test_tensorrt_fp32_engine_parity(tmp_path, sample_image):
def test_tensorrt_fp32_engine_parity(tmp_path, parkour_fixture_image):
"""Build and run a real engine; an ONNX parse alone is not TensorRT support.

Fixed batch 1 on purpose. An engine built with a dynamic batch profile
Expand All @@ -207,7 +207,7 @@ def test_tensorrt_fp32_engine_parity(tmp_path, sample_image):

assert backend.model_family == "ppyoloe"
_assert_raw_parity(
model, backend, sample_image, box_atol=2.0, score_atol=1e-2, batches=(1,)
model, backend, parkour_fixture_image, box_atol=2.0, score_atol=1e-2, batches=(1,)
)
_assert_public_parity(model, backend, sample_image, box_atol=0.5, score_atol=1e-2)
_assert_public_parity(model, backend, parkour_fixture_image, box_atol=0.5, score_atol=1e-2)

2 changes: 1 addition & 1 deletion tests/e2e/test_rfdetr_keypoint_parity.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

_REPO_ROOT = Path(__file__).resolve().parents[2]
_GOLDEN = _REPO_ROOT / "tests" / "data" / "rfdetr_keypoint_parkour_golden.json"
_PARKOUR = _REPO_ROOT / "libreyolo" / "assets" / "parkour.jpg"
_PARKOUR = _REPO_ROOT / "tests" / "data" / "parkour.jpg"
_DEFAULT_CKPT = _REPO_ROOT / "downloads" / "LibreRFDETRx-pose.pt"

# Tolerances. The oracle and LibreYOLO run the same weights, so agreement is
Expand Down
11 changes: 11 additions & 0 deletions tests/fixture_images.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""Test-only image fixtures.

``PARKOUR_FIXTURE`` is a frozen copy of the old sample photo, kept only for
parity and golden tests whose expected numbers depend on its exact pixels.
It is not shipped in the wheel and must never appear in user-facing material;
the sample image is ``libreyolo.SAMPLE_IMAGE`` (the Guggenheim Bilbao photo).
"""

from pathlib import Path

PARKOUR_FIXTURE = str(Path(__file__).resolve().parent / "data" / "parkour.jpg")
2 changes: 1 addition & 1 deletion tests/fixtures/matte8/generate_images.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
These procedural images are trivially redistributable (no third-party image
rights) and their sharp edges, gradients, and thin protrusions exercise the
resize/normalize + soft-edge behaviour a background-removal model must handle.
One real photo (the in-repo ``parkour.jpg``, a person) is copied in for a
One real photo (the test-only ``tests/data/parkour.jpg``, a person) is copied in for a
natural-image check. Run once to (re)generate ``images/``.
"""

Expand Down
Loading
Loading