16031aae96
CPU tests Workflow / Testing (ubuntu-latest, 3.12) (push) Failing after 1s
CPU tests Workflow / Testing (ubuntu-latest, 3.13) (push) Failing after 0s
Mypy Type Check / Type Check (push) Failing after 0s
Docs/Test WorkFlow / Test docs build (push) Failing after 1s
PR Conflict Labeler / labeling (push) Failing after 1s
Dependency resolution / Resolve [tflite] extra — Python 3.12 (push) Failing after 0s
Smoke Tests / try-all-models (ubuntu-latest, 3.10) (push) Failing after 0s
Smoke Tests / try-all-models (ubuntu-latest, 3.13) (push) Failing after 1s
CPU tests Workflow / build-pkg (push) Failing after 1s
CPU tests Workflow / Testing (ubuntu-latest, 3.10) (push) Failing after 0s
CPU tests Workflow / Testing (ubuntu-latest, 3.11) (push) Failing after 0s
Smoke Tests / try-all-models (macos-latest, 3.10) (push) Has been cancelled
Smoke Tests / try-all-models (macos-latest, 3.13) (push) Has been cancelled
Smoke Tests / try-all-models (windows-latest, 3.10) (push) Has been cancelled
Smoke Tests / try-all-models (windows-latest, 3.13) (push) Has been cancelled
CPU tests Workflow / Testing (macos-latest, 3.10) (push) Has been cancelled
CPU tests Workflow / Testing (macos-latest, 3.13) (push) Has been cancelled
CPU tests Workflow / Testing (windows-latest, 3.10) (push) Has been cancelled
CPU tests Workflow / Testing (windows-latest, 3.13) (push) Has been cancelled
CPU tests Workflow / testing-guardian (push) Has been cancelled
GPU tests Workflow / Testing (push) Has been cancelled
131 lines
4.8 KiB
Python
131 lines
4.8 KiB
Python
# ------------------------------------------------------------------------
|
|
# RF-DETR
|
|
# Copyright (c) 2025 Roboflow. All Rights Reserved.
|
|
# Licensed under the Apache License, Version 2.0 [see LICENSE for details]
|
|
# ------------------------------------------------------------------------
|
|
import socket
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from rfdetr.datasets._develop import (
|
|
_COCO_URLS,
|
|
_coco_val_images_complete,
|
|
_download_and_extract,
|
|
_download_lock,
|
|
_nonempty_file_exists,
|
|
)
|
|
from rfdetr.utilities.reproducibility import seed_all
|
|
|
|
_PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
|
_DATA_DIR = _PROJECT_ROOT / "data"
|
|
_COCO_HOST = "images.cocodataset.org"
|
|
_COCO_PORT = 80
|
|
|
|
|
|
def _is_online(host: str, port: int, timeout_s: float = 3.0) -> bool:
|
|
try:
|
|
with socket.create_connection((host, port), timeout=timeout_s):
|
|
return True
|
|
except OSError:
|
|
return False
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def download_coco_val() -> tuple[Path, Path]:
|
|
"""Download COCO val2017 images and annotations if not already present.
|
|
|
|
Returns:
|
|
Tuple containing the images root directory and annotations file path.
|
|
"""
|
|
if not _is_online(_COCO_HOST, _COCO_PORT):
|
|
pytest.skip("Offline environment, skipping COCO val2017 benchmark tests.")
|
|
|
|
images_root = _DATA_DIR / "val2017"
|
|
annotations_path = _DATA_DIR / "annotations" / "instances_val2017.json"
|
|
|
|
lock_path = _DATA_DIR / ".coco_download.lock"
|
|
with _download_lock(lock_path):
|
|
if not _coco_val_images_complete(images_root):
|
|
_download_and_extract(_COCO_URLS["val2017"], _DATA_DIR)
|
|
if not _nonempty_file_exists(annotations_path):
|
|
_download_and_extract(_COCO_URLS["annotations"], _DATA_DIR)
|
|
|
|
return images_root, annotations_path
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def download_coco_val_keypoints() -> tuple[Path, Path]:
|
|
"""Prepare COCO val images plus person-keypoint annotations for benchmark tests."""
|
|
if not _is_online(_COCO_HOST, _COCO_PORT):
|
|
pytest.skip("Offline environment, skipping COCO keypoint benchmark tests.")
|
|
|
|
images_root = _DATA_DIR / "val2017"
|
|
keypoint_annotations = _DATA_DIR / "annotations" / "person_keypoints_val2017.json"
|
|
|
|
lock_path = _DATA_DIR / ".coco_keypoint_download.lock"
|
|
with _download_lock(lock_path):
|
|
if not images_root.exists():
|
|
_download_and_extract(_COCO_URLS["val2017"], _DATA_DIR)
|
|
if not keypoint_annotations.exists():
|
|
_download_and_extract(_COCO_URLS["annotations"], _DATA_DIR)
|
|
|
|
return images_root, keypoint_annotations
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def download_coco_train_val_keypoints() -> Path:
|
|
"""Prepare full COCO train/val images plus person-keypoint annotations for release-qualification tests."""
|
|
if not _is_online(_COCO_HOST, _COCO_PORT):
|
|
pytest.skip("Offline environment, skipping full COCO keypoint training validation.")
|
|
|
|
lock_path = _DATA_DIR / ".coco_keypoint_train_val_download.lock"
|
|
with _download_lock(lock_path):
|
|
if not (_DATA_DIR / "train2017").exists():
|
|
_download_and_extract(_COCO_URLS["train2017"], _DATA_DIR)
|
|
if not (_DATA_DIR / "val2017").exists():
|
|
_download_and_extract(_COCO_URLS["val2017"], _DATA_DIR)
|
|
if (
|
|
not (_DATA_DIR / "annotations" / "person_keypoints_train2017.json").exists()
|
|
or not (_DATA_DIR / "annotations" / "person_keypoints_val2017.json").exists()
|
|
):
|
|
_download_and_extract(_COCO_URLS["annotations"], _DATA_DIR)
|
|
|
|
return _DATA_DIR
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def seed_everything(request: pytest.FixtureRequest) -> None:
|
|
"""Reset random, numpy, torch, and CUDA seeds before each test.
|
|
|
|
Defaults to seed 7. Override per-test via indirect parametrize::
|
|
|
|
@pytest.mark.parametrize("seed_everything", [42], indirect=True)
|
|
def test_foo(seed_everything): ...
|
|
|
|
Args:
|
|
request: Pytest fixture request that may carry an overridden seed.
|
|
"""
|
|
seed = request.param if hasattr(request, "param") else 7
|
|
seed_all(seed)
|
|
|
|
|
|
def pytest_collection_modifyitems(config: pytest.Config, items: list[pytest.Item]) -> None:
|
|
"""Reorder tests to prioritize long-running training test before xdist distribution.
|
|
|
|
This hook runs after collection but before xdist distributes tests to workers. By moving the training test to the
|
|
front, we ensure it gets scheduled early, maximizing parallel resource utilization.
|
|
"""
|
|
training_tests = []
|
|
other_tests = []
|
|
|
|
for item in items:
|
|
# Prioritize the synthetic training convergence tests (detection + segmentation)
|
|
if "training" in item.nodeid:
|
|
training_tests.append(item)
|
|
else:
|
|
other_tests.append(item)
|
|
|
|
# Reorder: training tests first, then everything else
|
|
items[:] = training_tests + other_tests
|