Files
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

147 lines
5.2 KiB
Python

# ------------------------------------------------------------------------
# RF-DETR
# Copyright (c) 2025 Roboflow. All Rights Reserved.
# Licensed under the Apache License, Version 2.0 [see LICENSE for details]
# ------------------------------------------------------------------------
import os
from unittest.mock import patch
import pytest
from rfdetr.assets import ModelWeightAsset, ModelWeights, ModelWeightsBase
from rfdetr.assets.model_weights import get_model_cache_dir
class TestGetModelCacheDir:
"""Verify get_model_cache_dir reads RF_HOME with correct default."""
def test_default_when_rf_home_not_set(self, monkeypatch):
"""Returns ~/.roboflow/models when RF_HOME env var is absent."""
monkeypatch.delenv("RF_HOME", raising=False)
expected = os.path.normpath(os.path.expanduser("~/.roboflow/models"))
assert get_model_cache_dir() == expected
def test_custom_rf_home_absolute_path(self, monkeypatch, tmp_path):
"""Returns exact RF_HOME value when set to an absolute path."""
monkeypatch.setenv("RF_HOME", str(tmp_path))
assert get_model_cache_dir() == str(tmp_path)
def test_tilde_in_rf_home_is_expanded(self, monkeypatch):
"""Tilde in RF_HOME is expanded; result contains no literal tilde."""
monkeypatch.setenv("RF_HOME", "~/custom_rfdetr_cache")
result = get_model_cache_dir()
assert result == os.path.normpath(os.path.expanduser("~/custom_rfdetr_cache"))
assert "~" not in result
def test_returns_string(self, monkeypatch):
"""Return value is always a str, not a Path."""
monkeypatch.delenv("RF_HOME", raising=False)
assert isinstance(get_model_cache_dir(), str)
def test_from_filename_found():
"""Test from_filename with valid filename."""
asset = ModelWeights.from_filename("rf-detr-base.pth")
assert asset is not None
assert isinstance(asset, ModelWeightAsset)
assert asset.filename == "rf-detr-base.pth"
assert asset.url.startswith("http")
assert "rf-detr-base-coco.pth" in asset.url
def test_from_filename_not_found():
"""Test from_filename with invalid filename."""
asset = ModelWeights.from_filename("nonexistent-model.pth")
assert asset is None
def test_get_url():
"""Test get_url class method."""
url = ModelWeights.get_url("rf-detr-base.pth")
assert url is not None
assert isinstance(url, str)
assert url.startswith("http")
assert "rf-detr-base-coco.pth" in url
def test_get_url_not_found():
"""Test get_url with invalid filename."""
url = ModelWeights.get_url("nonexistent-model.pth")
assert url is None
def test_get_md5():
"""Test get_md5 class method."""
md5 = ModelWeights.get_md5("rf-detr-base.pth")
# MD5 may be None if not yet computed
assert md5 is None or isinstance(md5, str)
# If MD5 exists, verify format
if md5 is not None:
assert len(md5) == 32
assert all(c in "0123456789abcdef" for c in md5.lower())
def test_list_models():
"""Test list_models returns all model filenames."""
models = ModelWeights.list_models()
assert isinstance(models, list)
assert len(models) > 0
assert "rf-detr-base.pth" in models
assert "rf-detr-large.pth" in models
# All entries should be strings
assert all(isinstance(m, str) for m in models)
@pytest.mark.parametrize("asset", [pytest.param(a, id=a.filename) for a in ModelWeights])
def test_all_assets_have_valid_urls(asset: ModelWeightAsset) -> None:
"""Test that all assets have valid URLs."""
assert asset.url.startswith("http")
assert len(asset.url) > 20 # Reasonable minimum URL length
@pytest.mark.parametrize("asset", [pytest.param(a, id=a.filename) for a in ModelWeights])
def test_all_assets_have_valid_filenames(asset: ModelWeightAsset) -> None:
"""Test that all assets have valid filenames."""
assert len(asset.filename) > 0
assert asset.filename.endswith((".pth", ".pt"))
def test_filenames_are_unique():
"""Test that all filenames are unique (prevent accidental duplicates)."""
filenames = [asset.filename for asset in ModelWeights]
assert len(filenames) == len(set(filenames)), "Duplicate filenames detected"
def test_model_weight_asset_optional_md5():
"""Test that MD5 hash is optional (important for new models)."""
asset = ModelWeightAsset(filename="test-model.pth", url="https://example.com/test-model.pth")
assert asset.md5_hash is None, "MD5 hash should be optional"
def test_model_weights_inherits_from_base():
"""Test inheritance for compile-time safety contract."""
assert issubclass(ModelWeights, ModelWeightsBase), (
"ModelWeights must inherit from ModelWeightsBase for compatibility"
)
def test_rfdetr_large_deprecated_emits_future_warning() -> None:
"""RFDETRLargeDeprecated emits FutureWarning on instantiation via the pyDeprecate class decorator."""
from rfdetr.variants import RFDETRLargeDeprecated
# The proxy uses num_warns=1; reset counter so this test is order-independent
# regardless of whether another test already triggered the warning in this session.
RFDETRLargeDeprecated._cfg.warned = 0
with patch("rfdetr.detr.RFDETR.__init__", return_value=None):
with pytest.warns(FutureWarning):
RFDETRLargeDeprecated()