Files
roboflow--rf-detr/tests/utilities/test_package.py
T
wehub-resource-sync 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
chore: import upstream snapshot with attribution
2026-07-13 12:26:24 +08:00

270 lines
11 KiB
Python

# ------------------------------------------------------------------------
# RF-DETR
# Copyright (c) 2025 Roboflow. All Rights Reserved.
# Licensed under the Apache License, Version 2.0 [see LICENSE for details]
# ------------------------------------------------------------------------
"""Tests for package metadata helpers and structural import paths."""
import subprocess
import sys
from unittest.mock import patch
import pytest
from rfdetr.utilities.package import get_sha
def test_get_sha_marks_dirty_worktree_when_diff_command_returns_exit_code_1() -> None:
"""A diff exit code of 1 should report uncommitted changes, not unknown."""
def _fake_check_output(command: list[str], cwd: str | None = None) -> bytes:
if command[:3] == ["git", "rev-parse", "HEAD"]:
return b"abc123\n"
if command[:4] == ["git", "rev-parse", "--abbrev-ref", "HEAD"]:
return b"feature/test\n"
raise AssertionError(f"Unexpected command: {command!r}")
class _RunResult:
def __init__(self, returncode: int) -> None:
self.returncode = returncode
with (
patch("rfdetr.utilities.package.subprocess.check_output", side_effect=_fake_check_output),
patch("rfdetr.utilities.package.subprocess.run", return_value=_RunResult(returncode=1)),
):
sha = get_sha()
assert sha == "sha: abc123, status: has uncommitted changes, branch: feature/test"
def test_peft_not_imported_eagerly_on_backbone_import_characterization() -> None:
"""Importing backbone.backbone must NOT pull peft into sys.modules (peft is optional).
This characterization test captures the invariant introduced in PR 1 (chore/packaging-peft-lora): after the lazy-
import refactor, importing backbone at module-load time must not trigger a top-level ``from peft import PeftModel``.
"""
result = subprocess.run(
[
sys.executable,
"-c",
(
"import sys; "
"import rfdetr.models.backbone.backbone; "
"assert 'peft' not in sys.modules, "
"'peft was eagerly imported by backbone.backbone'"
),
],
capture_output=True,
text=True,
check=False,
)
assert result.returncode == 0, (
"Subprocess for backbone import failed:\n"
f"return code: {result.returncode}\n"
f"stdout:\n{result.stdout}\n"
f"stderr:\n{result.stderr}"
)
class TestImportPaths:
"""Structural tests for the detr.py → inference.py + variants.py split (PR 6).
After the split:
- ``rfdetr.inference`` exports ``ModelContext`` and ``_build_model_context``
- ``rfdetr.variants`` exports all 15 concrete model classes
- ``rfdetr.detr`` re-exports both for backward compatibility
- ``rfdetr`` (top-level) continues to export public names unchanged
"""
def test_model_context_importable_from_inference(self) -> None:
"""ModelContext must be importable from the new rfdetr.inference module."""
from rfdetr.inference import ModelContext
assert ModelContext is not None
def test_build_model_context_importable_from_inference(self) -> None:
"""_build_model_context must be importable from rfdetr.inference."""
from rfdetr.inference import _build_model_context
assert callable(_build_model_context)
def test_rfdetr_large_importable_from_variants(self) -> None:
"""RFDETRLarge must be importable from the new rfdetr.variants module."""
from rfdetr.variants import RFDETRLarge
assert RFDETRLarge is not None
def test_variants_import_first_does_not_trigger_circular_import(self) -> None:
"""Importing variants before detr must still preserve shared class identity."""
result = subprocess.run(
[
sys.executable,
"-c",
(
"from rfdetr.variants import RFDETRLarge; "
"from rfdetr.detr import RFDETRLarge as FromDetr; "
"assert RFDETRLarge is FromDetr"
),
],
capture_output=True,
text=True,
check=False,
)
assert result.returncode == 0, (
"Subprocess for variants-first import failed:\n"
f"return code: {result.returncode}\n"
f"stdout:\n{result.stdout}\n"
f"stderr:\n{result.stderr}"
)
@pytest.mark.parametrize(
"class_name",
[
pytest.param("RFDETRBase", id="base"),
pytest.param("RFDETRKeypointPreview", id="keypoint-preview"),
pytest.param("RFDETRNano", id="nano"),
pytest.param("RFDETRSmall", id="small"),
pytest.param("RFDETRMedium", id="medium"),
pytest.param("RFDETRLargeDeprecated", id="large-deprecated"),
pytest.param("RFDETRLarge", id="large"),
pytest.param("RFDETRSeg", id="seg-base"),
pytest.param("RFDETRSegPreview", id="seg-preview"),
pytest.param("RFDETRSegNano", id="seg-nano"),
pytest.param("RFDETRSegSmall", id="seg-small"),
pytest.param("RFDETRSegMedium", id="seg-medium"),
pytest.param("RFDETRSegLarge", id="seg-large"),
pytest.param("RFDETRSegXLarge", id="seg-xlarge"),
pytest.param("RFDETRSeg2XLarge", id="seg-2xlarge"),
],
)
def test_all_variant_classes_importable_from_variants(self, class_name: str) -> None:
"""Every concrete variant class must be importable from rfdetr.variants."""
import rfdetr.variants as variants_mod
cls = getattr(variants_mod, class_name, None)
assert cls is not None, f"{class_name} not found in rfdetr.variants"
def test_model_context_backward_compat_from_detr(self) -> None:
"""ModelContext must remain importable from rfdetr.detr (backward compat)."""
from rfdetr.detr import ModelContext
assert ModelContext is not None
def test_rfdetr_large_backward_compat_from_detr(self) -> None:
"""RFDETRLarge must remain importable from rfdetr.detr (backward compat)."""
from rfdetr.detr import RFDETRLarge
assert RFDETRLarge is not None
def test_rfdetr_large_importable_from_top_level(self) -> None:
"""RFDETRLarge must remain importable from rfdetr (top-level package)."""
from rfdetr import RFDETRLarge
assert RFDETRLarge is not None
def test_model_context_importable_from_top_level(self) -> None:
"""ModelContext must remain importable from rfdetr (top-level package)."""
from rfdetr import ModelContext
assert ModelContext is not None
def test_top_level_import_sets_numpy_complex_alias(self) -> None:
"""Verify rfdetr shim sets np.complex_ in a fresh interpreter with complex_ absent.
Runs in a subprocess so the shim code path is actually executed — importing rfdetr inside pytest is a no-op
because rfdetr is already cached in sys.modules.
"""
result = subprocess.run(
[
sys.executable,
"-c",
(
"import numpy\n"
"if hasattr(numpy, 'complex_'):\n"
" del numpy.complex_\n"
"import rfdetr\n"
"assert hasattr(numpy, 'complex_'), 'shim did not set numpy.complex_'\n"
"assert numpy.complex_ is numpy.complex128, 'complex_ must alias complex128'\n"
),
],
capture_output=True,
text=True,
check=False,
)
assert result.returncode == 0, (
"Subprocess for NumPy complex_ shim failed:\n"
f"return code: {result.returncode}\n"
f"stdout:\n{result.stdout}\n"
f"stderr:\n{result.stderr}"
)
def test_identity_across_import_paths(self) -> None:
"""The same class object must be returned regardless of import path.
This ensures re-exports are true re-exports (not copies) so that isinstance() checks work across all import
paths.
"""
import rfdetr
from rfdetr.detr import ModelContext as FromDetr
from rfdetr.detr import RFDETRLarge as LargeFromDetr
from rfdetr.inference import ModelContext as FromInference
from rfdetr.variants import RFDETRLarge as LargeFromVariants
assert FromDetr is FromInference, (
"rfdetr.detr.ModelContext and rfdetr.inference.ModelContext must be the same object"
)
assert LargeFromDetr is LargeFromVariants, (
"rfdetr.detr.RFDETRLarge and rfdetr.variants.RFDETRLarge must be the same object"
)
assert rfdetr.RFDETRLarge is LargeFromVariants, (
"top-level rfdetr.RFDETRLarge and rfdetr.variants.RFDETRLarge must be the same object"
)
assert rfdetr.ModelContext is FromInference, (
"top-level rfdetr.ModelContext and rfdetr.inference.ModelContext must be the same object"
)
def test_build_model_context_backward_compat_from_detr(self) -> None:
"""_build_model_context must remain importable from rfdetr.detr (backward compat)."""
from rfdetr.detr import _build_model_context
assert callable(_build_model_context)
def test_getattr_raises_for_unknown_names(self) -> None:
"""Accessing an unknown name via rfdetr.detr must raise AttributeError."""
import rfdetr.detr as detr_mod
with pytest.raises(AttributeError, match="has no attribute"):
_ = detr_mod._this_name_does_not_exist_12345
def test_dir_includes_lazy_exports(self) -> None:
"""dir(rfdetr.detr) must include all lazy re-export names."""
import rfdetr.detr as detr_mod
names = dir(detr_mod)
assert "ModelContext" in names, "ModelContext missing from dir(rfdetr.detr)"
assert "RFDETRLarge" in names, "RFDETRLarge missing from dir(rfdetr.detr)"
assert "RFDETRBase" in names, "RFDETRBase missing from dir(rfdetr.detr)"
def test_detr_first_import_order_preserves_identity(self) -> None:
"""Importing detr before variants must preserve object identity for variant classes."""
result = subprocess.run(
[
sys.executable,
"-c",
(
"from rfdetr.detr import RFDETRLarge; "
"from rfdetr.variants import RFDETRLarge as FromVariants; "
"assert RFDETRLarge is FromVariants"
),
],
capture_output=True,
text=True,
check=False,
)
assert result.returncode == 0, (
"Subprocess for detr-first import failed:\n"
f"return code: {result.returncode}\n"
f"stdout:\n{result.stdout}\n"
f"stderr:\n{result.stderr}"
)