chore: import upstream snapshot with attribution
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

This commit is contained in:
wehub-resource-sync
2026-07-13 12:26:24 +08:00
commit 16031aae96
343 changed files with 88674 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
# ------------------------------------------------------------------------
# RF-DETR
# Copyright (c) 2025 Roboflow. All Rights Reserved.
# Licensed under the Apache License, Version 2.0 [see LICENSE for details]
# ------------------------------------------------------------------------
+143
View File
@@ -0,0 +1,143 @@
# ------------------------------------------------------------------------
# RF-DETR
# Copyright (c) 2025 Roboflow. All Rights Reserved.
# Licensed under the Apache License, Version 2.0 [see LICENSE for details]
# ------------------------------------------------------------------------
"""Tests for YAML config files in configs/ — PTL Ch4/T6.
Verifies that every example YAML config file:
- exists on disk,
- parses as valid YAML,
- contains a ``model`` section with ``model_config`` and ``train_config``,
- references the expected model class_path, and
- segmentation configs use SegmentationTrainConfig.
"""
import pathlib
import pytest
import yaml
CONFIGS_DIR = pathlib.Path(__file__).parent.parent.parent / "configs"
DETECTION_CONFIGS = [
"rfdetr_nano",
"rfdetr_small",
"rfdetr_medium",
"rfdetr_base",
"rfdetr_large",
]
SEGMENTATION_CONFIGS = [
"rfdetr_seg_nano",
"rfdetr_seg_small",
"rfdetr_seg_medium",
"rfdetr_seg_large",
"rfdetr_seg_xlarge",
"rfdetr_seg_2xlarge",
]
ALL_CONFIGS = DETECTION_CONFIGS + SEGMENTATION_CONFIGS
# Maps filename stem → expected model_config class_path.
EXPECTED_MODEL_CLASS = {
"rfdetr_nano": "rfdetr.config.RFDETRNanoConfig",
"rfdetr_small": "rfdetr.config.RFDETRSmallConfig",
"rfdetr_medium": "rfdetr.config.RFDETRMediumConfig",
"rfdetr_base": "rfdetr.config.RFDETRBaseConfig",
"rfdetr_large": "rfdetr.config.RFDETRLargeConfig",
"rfdetr_seg_nano": "rfdetr.config.RFDETRSegNanoConfig",
"rfdetr_seg_small": "rfdetr.config.RFDETRSegSmallConfig",
"rfdetr_seg_medium": "rfdetr.config.RFDETRSegMediumConfig",
"rfdetr_seg_large": "rfdetr.config.RFDETRSegLargeConfig",
"rfdetr_seg_xlarge": "rfdetr.config.RFDETRSegXLargeConfig",
"rfdetr_seg_2xlarge": "rfdetr.config.RFDETRSeg2XLargeConfig",
}
def _load(name: str) -> dict:
"""Parse a config file by stem name and return its dict."""
return yaml.safe_load((CONFIGS_DIR / f"{name}.yaml").read_text())
# ---------------------------------------------------------------------------
# File existence
# ---------------------------------------------------------------------------
class TestConfigFilesExist:
"""Every expected YAML config file must be present on disk."""
@pytest.mark.parametrize("name", ALL_CONFIGS)
def test_config_file_exists(self, name):
"""configs/{name}.yaml must exist."""
assert (CONFIGS_DIR / f"{name}.yaml").exists(), f"Missing config file: {name}.yaml"
# ---------------------------------------------------------------------------
# YAML validity
# ---------------------------------------------------------------------------
class TestConfigFilesValidYAML:
"""Each file must be parseable as YAML and produce a mapping."""
@pytest.mark.parametrize("name", ALL_CONFIGS)
def test_config_is_valid_yaml(self, name):
"""yaml.safe_load must succeed and return a dict."""
data = _load(name)
assert isinstance(data, dict), f"{name}.yaml did not parse to a dict"
# ---------------------------------------------------------------------------
# Structure
# ---------------------------------------------------------------------------
class TestConfigStructure:
"""Each YAML must have a model section with model_config and train_config."""
@pytest.mark.parametrize("name", ALL_CONFIGS)
def test_has_model_section(self, name):
"""Top-level 'model' key must be present."""
assert "model" in _load(name), f"{name}.yaml missing 'model' section"
@pytest.mark.parametrize("name", ALL_CONFIGS)
def test_has_model_config(self, name):
"""model.model_config must be present."""
assert "model_config" in _load(name)["model"], f"{name}.yaml missing model.model_config"
@pytest.mark.parametrize("name", ALL_CONFIGS)
def test_has_train_config(self, name):
"""model.train_config must be present."""
assert "train_config" in _load(name)["model"], f"{name}.yaml missing model.train_config"
# ---------------------------------------------------------------------------
# Class paths
# ---------------------------------------------------------------------------
class TestConfigClassPaths:
"""model_config class_path must match the expected model variant."""
@pytest.mark.parametrize("name", ALL_CONFIGS)
def test_model_config_class_path(self, name):
"""model.model_config.class_path must match the variant."""
got = _load(name)["model"]["model_config"]["class_path"]
want = EXPECTED_MODEL_CLASS[name]
assert got == want, f"{name}.yaml: expected class_path {want!r}, got {got!r}"
@pytest.mark.parametrize("name", SEGMENTATION_CONFIGS)
def test_seg_uses_segmentation_train_config(self, name):
"""Segmentation configs must use SegmentationTrainConfig."""
got = _load(name)["model"]["train_config"]["class_path"]
assert got == "rfdetr.config.SegmentationTrainConfig", (
f"{name}.yaml: train_config must use SegmentationTrainConfig, got {got!r}"
)
@pytest.mark.parametrize("name", DETECTION_CONFIGS)
def test_det_uses_train_config(self, name):
"""Detection configs must use TrainConfig (not a subclass)."""
got = _load(name)["model"]["train_config"]["class_path"]
assert got == "rfdetr.config.TrainConfig", f"{name}.yaml: train_config must use TrainConfig, got {got!r}"
+29
View File
@@ -0,0 +1,29 @@
# ------------------------------------------------------------------------
# RF-DETR
# Copyright (c) 2025 Roboflow. All Rights Reserved.
# Licensed under the Apache License, Version 2.0 [see LICENSE for details]
# ------------------------------------------------------------------------
"""Tests for the CLI entry point configuration."""
import pathlib
import re
class TestEntryPoint:
"""[project.scripts] in pyproject.toml uses the correct CLI entry point."""
def _read_entry_point(self) -> str:
"""Return the rfdetr console_scripts value from pyproject.toml."""
root = pathlib.Path(__file__).parent.parent.parent
content = (root / "pyproject.toml").read_text()
m = re.search(r"\[project\.scripts\].*?rfdetr\s*=\s*\"([^\"]+)\"", content, re.DOTALL)
assert m, "rfdetr entry not found in [project.scripts]"
return m.group(1)
def test_entry_point_value(self):
"""Rfdetr entry point must be rfdetr.cli:main."""
assert self._read_entry_point() == "rfdetr.cli:main"
def test_entry_point_not_legacy(self):
"""Entry point must no longer reference rfdetr.cli.main:trainer."""
assert self._read_entry_point() != "rfdetr.cli.main:trainer"
+195
View File
@@ -0,0 +1,195 @@
# ------------------------------------------------------------------------
# RF-DETR
# Copyright (c) 2025 Roboflow. All Rights Reserved.
# Licensed under the Apache License, Version 2.0 [see LICENSE for details]
# ------------------------------------------------------------------------
"""CLI smoke tests and YAML roundtrip tests — PTL Ch4/T7.
Smoke tests run RFDETRCli in-process with args=['--help'] / ['fit', '--help'] / ['validate', '--help'] and assert
SystemExit(0) — no subprocess needed.
YAML roundtrip tests load each example config with yaml.safe_load, import the class_path, construct the config object
with the YAML init_args, and verify every specified field survived the round-trip.
"""
import importlib
import pathlib
import pytest
import yaml
CONFIGS_DIR = pathlib.Path(__file__).parent.parent.parent / "configs"
ALL_CONFIGS = [
"rfdetr_nano",
"rfdetr_small",
"rfdetr_medium",
"rfdetr_base",
"rfdetr_large",
"rfdetr_seg_nano",
"rfdetr_seg_small",
"rfdetr_seg_medium",
"rfdetr_seg_large",
"rfdetr_seg_xlarge",
"rfdetr_seg_2xlarge",
]
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def _run_cli(*args: str) -> int:
"""Run RFDETRCli in-process with the given args; return the SystemExit code."""
from rfdetr.training.cli import RFDETRCli
from rfdetr.training.module_data import RFDETRDataModule
from rfdetr.training.module_model import RFDETRModelModule
with pytest.raises(SystemExit) as exc_info:
RFDETRCli(RFDETRModelModule, RFDETRDataModule, args=list(args))
return exc_info.value.code
def _load(name: str) -> dict:
return yaml.safe_load((CONFIGS_DIR / f"{name}.yaml").read_text())
def _instantiate(class_path: str, init_args: dict) -> object:
"""Import class_path and construct an instance with init_args."""
module_path, class_name = class_path.rsplit(".", 1)
cls = getattr(importlib.import_module(module_path), class_name)
return cls(**init_args)
# ---------------------------------------------------------------------------
# Smoke tests
# ---------------------------------------------------------------------------
class TestCLIEntrypoint:
"""Module entrypoint and CLI import tests."""
def test_python_module_entrypoint_runs(self) -> None:
"""Python -m rfdetr --help exits 0 and mentions rfdetr."""
import subprocess
import sys
result = subprocess.run(
[sys.executable, "-m", "rfdetr", "--help"],
capture_output=True,
text=True,
timeout=30,
)
assert result.returncode == 0
assert "rfdetr" in result.stdout.lower() or "rfdetr" in result.stderr.lower()
def test_cli_main_is_importable(self) -> None:
"""rfdetr.cli module is importable and exposes a callable main."""
import importlib
mod = importlib.import_module("rfdetr.cli")
assert callable(getattr(mod, "main", None))
class TestCLIHelp:
"""Rfdetr --help and subcommand --help must exit 0."""
def test_top_level_help(self):
"""Rfdetr --help exits with code 0."""
assert _run_cli("--help") == 0
def test_fit_help(self):
"""Rfdetr fit --help exits with code 0."""
assert _run_cli("fit", "--help") == 0
def test_validate_help(self):
"""Rfdetr validate --help exits with code 0."""
assert _run_cli("validate", "--help") == 0
def test_fit_help_exposes_model_config(self):
"""Rfdetr fit --help output lists model.model_config arguments."""
import io
import sys
buf = io.StringIO()
old_stdout = sys.stdout
sys.stdout = buf
try:
_run_cli("fit", "--help")
finally:
sys.stdout = old_stdout
assert "model_config" in buf.getvalue()
def test_fit_help_exposes_train_config(self):
"""Rfdetr fit --help output lists model.train_config arguments."""
import io
import sys
buf = io.StringIO()
old_stdout = sys.stdout
sys.stdout = buf
try:
_run_cli("fit", "--help")
finally:
sys.stdout = old_stdout
assert "train_config" in buf.getvalue()
# ---------------------------------------------------------------------------
# YAML roundtrip — model_config
# ---------------------------------------------------------------------------
class TestModelConfigRoundtrip:
"""model_config init_args from YAML construct a valid config with matching values."""
@pytest.mark.parametrize("name", ALL_CONFIGS)
def test_model_config_fields_survive_roundtrip(self, name):
"""Every field in model_config.init_args is preserved after instantiation."""
data = _load(name)
mc_section = data["model"]["model_config"]
class_path = mc_section["class_path"]
init_args = mc_section.get("init_args", {})
mc = _instantiate(class_path, init_args)
for field, value in init_args.items():
assert getattr(mc, field) == value, (
f"{name}.yaml: model_config.{field} expected {value!r}, got {getattr(mc, field)!r}"
)
# ---------------------------------------------------------------------------
# YAML roundtrip — train_config
# ---------------------------------------------------------------------------
class TestTrainConfigRoundtrip:
"""train_config init_args from YAML construct a valid config with matching values."""
@pytest.mark.parametrize("name", ALL_CONFIGS)
def test_train_config_fields_survive_roundtrip(self, name, tmp_path):
"""Every field in train_config.init_args is preserved after instantiation.
dataset_dir is rewritten to tmp_path so path expansion doesn't fail on the placeholder /data/coco value.
TrainConfig.expand_paths() converts relative paths containing separators to absolute, so both sides are
normalised with os.path.abspath before comparison.
"""
import os
data = _load(name)
tc_section = data["model"]["train_config"]
class_path = tc_section["class_path"]
init_args = dict(tc_section.get("init_args", {}))
# Substitute placeholder dataset_dir with a real tmp_path.
init_args["dataset_dir"] = str(tmp_path)
tc = _instantiate(class_path, init_args)
for field, value in init_args.items():
actual = getattr(tc, field)
# TrainConfig.expand_paths() resolves relative path strings to
# absolute, so normalise both sides for string path fields.
if isinstance(value, str) and (os.sep in value or "/" in value):
value = os.path.abspath(value)
assert actual == value, f"{name}.yaml: train_config.{field} expected {value!r}, got {actual!r}"