Files
wehub-resource-sync 9194ef5abd
Docs/Test Workflow / Test docs build (push) Failing after 0s
Check links & references / links-check (push) Failing after 1s
Pytest/Test Workflow / Import Test and Pytest Run (ubuntu-latest, 3.10) (push) Failing after 0s
Pytest/Test Workflow / Import Test and Pytest Run (ubuntu-latest, 3.11) (push) Failing after 0s
PR Conflict Labeler / main (push) Failing after 2s
Pytest/Test Workflow / Import Test and Pytest Run (ubuntu-latest, 3.12) (push) Failing after 2s
Pytest/Test Workflow / Import Test and Pytest Run (ubuntu-latest, 3.13) (push) Failing after 0s
Pytest/Test Workflow / Build this Package (push) Failing after 5s
Pytest/Test Workflow / Import Test and Pytest Run (macos-latest, 3.10) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (macos-latest, 3.11) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (macos-latest, 3.12) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (macos-latest, 3.13) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (windows-latest, 3.10) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (windows-latest, 3.11) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (windows-latest, 3.12) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (windows-latest, 3.13) (push) Has been cancelled
Pytest/Test Workflow / testing-guardian (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:06:10 +08:00

386 lines
14 KiB
Python

"""Tests for show_progress parameter on dataset load/save operations."""
import json
import os
from pathlib import Path
from unittest.mock import patch
import cv2
import numpy as np
import pytest
from tqdm.auto import tqdm as _real_tqdm
from supervision import DetectionDataset
def _create_dummy_yolo_dataset(root: str, num_images: int = 3) -> tuple[str, str, str]:
images_dir = os.path.join(root, "images")
labels_dir = os.path.join(root, "labels")
os.makedirs(images_dir, exist_ok=True)
os.makedirs(labels_dir, exist_ok=True)
for i in range(num_images):
img = np.zeros((100, 100, 3), dtype=np.uint8)
cv2.imwrite(os.path.join(images_dir, f"img_{i}.jpg"), img)
with open(os.path.join(labels_dir, f"img_{i}.txt"), "w") as f:
f.write("0 0.5 0.5 0.2 0.2\n")
data_yaml = os.path.join(root, "data.yaml")
with open(data_yaml, "w") as f:
f.write("names:\n - class_0\nnc: 1\n")
return images_dir, labels_dir, data_yaml
def _create_dummy_coco_dataset(root: str, num_images: int = 3) -> tuple[str, str]:
images_dir = os.path.join(root, "images")
os.makedirs(images_dir, exist_ok=True)
coco = {
"images": [],
"annotations": [],
"categories": [{"id": 0, "name": "class_0", "supercategory": "none"}],
}
for i in range(num_images):
img = np.zeros((100, 100, 3), dtype=np.uint8)
fname = f"img_{i}.jpg"
cv2.imwrite(os.path.join(images_dir, fname), img)
coco["images"].append(
{
"id": i,
"file_name": fname,
"width": 100,
"height": 100,
}
)
coco["annotations"].append(
{
"id": i,
"image_id": i,
"category_id": 0,
"bbox": [10, 10, 20, 20],
"area": 400,
"segmentation": [],
"iscrowd": 0,
}
)
annotations_path = os.path.join(root, "annotations.json")
with open(annotations_path, "w") as f:
json.dump(coco, f)
return images_dir, annotations_path
def _create_dummy_pascal_voc_dataset(root: str, num_images: int = 3) -> tuple[str, str]:
images_dir = os.path.join(root, "images")
annotations_dir = os.path.join(root, "annotations")
os.makedirs(images_dir, exist_ok=True)
os.makedirs(annotations_dir, exist_ok=True)
for i in range(num_images):
img = np.zeros((100, 100, 3), dtype=np.uint8)
cv2.imwrite(os.path.join(images_dir, f"img_{i}.jpg"), img)
xml_content = f"""<?xml version="1.0" ?>
<annotation>
<folder>images</folder>
<filename>img_{i}.jpg</filename>
<size>
<width>100</width>
<height>100</height>
<depth>3</depth>
</size>
<object>
<name>class_0</name>
<bndbox>
<xmin>10</xmin>
<ymin>10</ymin>
<xmax>30</xmax>
<ymax>30</ymax>
</bndbox>
</object>
</annotation>"""
with open(os.path.join(annotations_dir, f"img_{i}.xml"), "w") as f:
f.write(xml_content)
return images_dir, annotations_dir
# ---------------------------------------------------------------------------
# Fixtures — raw file trees (used by from_* tests that call the loader under patch)
# ---------------------------------------------------------------------------
@pytest.fixture
def yolo_dir(tmp_path: Path) -> tuple[str, str, str]:
"""YOLO images, labels, and data.yaml on disk."""
return _create_dummy_yolo_dataset(str(tmp_path))
@pytest.fixture
def coco_dir(tmp_path: Path) -> tuple[str, str]:
"""COCO images directory and annotations JSON on disk."""
return _create_dummy_coco_dataset(str(tmp_path))
@pytest.fixture
def pascal_voc_dir(tmp_path: Path) -> tuple[str, str]:
"""Pascal VOC images and XML annotations on disk."""
return _create_dummy_pascal_voc_dataset(str(tmp_path))
# ---------------------------------------------------------------------------
# Fixtures — pre-loaded DetectionDataset (used by as_* and backward-compat tests)
# ---------------------------------------------------------------------------
@pytest.fixture
def yolo_dataset(yolo_dir: tuple[str, str, str]) -> DetectionDataset:
"""DetectionDataset loaded from a dummy YOLO dataset."""
images_dir, labels_dir, data_yaml = yolo_dir
return DetectionDataset.from_yolo(
images_directory_path=images_dir,
annotations_directory_path=labels_dir,
data_yaml_path=data_yaml,
)
@pytest.fixture
def coco_dataset(coco_dir: tuple[str, str]) -> DetectionDataset:
"""DetectionDataset loaded from a dummy COCO dataset."""
images_dir, annotations_path = coco_dir
return DetectionDataset.from_coco(
images_directory_path=images_dir,
annotations_path=annotations_path,
)
@pytest.fixture
def pascal_voc_dataset(pascal_voc_dir: tuple[str, str]) -> DetectionDataset:
"""DetectionDataset loaded from a dummy Pascal VOC dataset."""
images_dir, annotations_dir = pascal_voc_dir
return DetectionDataset.from_pascal_voc(
images_directory_path=images_dir,
annotations_directory_path=annotations_dir,
)
# ---------------------------------------------------------------------------
# Tests
# ---------------------------------------------------------------------------
_YOLO_TQDM = "supervision.dataset.formats.yolo.tqdm"
_COCO_TQDM = "supervision.dataset.formats.coco.tqdm"
_PASCAL_TQDM = "supervision.dataset.formats.pascal_voc.tqdm"
_UTILS_TQDM = "supervision.dataset.utils.tqdm"
class TestYoloProgress:
@patch(_YOLO_TQDM, wraps=_real_tqdm)
def test_from_yolo_no_progress_by_default(
self, mock_tqdm: object, yolo_dir: tuple[str, str, str]
):
"""YOLO load does not show progress bar by default."""
images_dir, labels_dir, data_yaml = yolo_dir
ds = DetectionDataset.from_yolo(
images_directory_path=images_dir,
annotations_directory_path=labels_dir,
data_yaml_path=data_yaml,
)
assert mock_tqdm.call_args[1]["disable"] is True
assert len(ds) == 3
@patch(_YOLO_TQDM, wraps=_real_tqdm)
def test_from_yolo_with_progress(
self, mock_tqdm: object, yolo_dir: tuple[str, str, str]
):
"""YOLO load shows progress bar when show_progress=True."""
images_dir, labels_dir, data_yaml = yolo_dir
ds = DetectionDataset.from_yolo(
images_directory_path=images_dir,
annotations_directory_path=labels_dir,
data_yaml_path=data_yaml,
show_progress=True,
)
assert mock_tqdm.call_args[1]["disable"] is False
assert len(ds) == 3
@patch(_YOLO_TQDM, wraps=_real_tqdm)
def test_as_yolo_with_progress(
self, mock_tqdm: object, yolo_dataset: DetectionDataset, tmp_path: Path
):
"""YOLO save shows progress bar when show_progress=True."""
out = tmp_path / "output"
yolo_dataset.as_yolo(
images_directory_path=str(out / "images"),
annotations_directory_path=str(out / "labels"),
data_yaml_path=str(out / "data.yaml"),
show_progress=True,
)
assert mock_tqdm.call_args[1]["disable"] is False
@patch(_YOLO_TQDM, wraps=_real_tqdm)
def test_as_yolo_no_progress_by_default(
self, mock_tqdm: object, yolo_dataset: DetectionDataset, tmp_path: Path
):
"""Saving YOLO annotations does not show progress bar by default."""
yolo_dataset.as_yolo(
annotations_directory_path=str(tmp_path / "output" / "labels")
)
assert mock_tqdm.call_args[1]["disable"] is True
class TestCocoProgress:
@patch(_COCO_TQDM, wraps=_real_tqdm)
def test_from_coco_no_progress_by_default(
self, mock_tqdm: object, coco_dir: tuple[str, str]
):
"""COCO load does not show progress bar by default."""
images_dir, annotations_path = coco_dir
ds = DetectionDataset.from_coco(
images_directory_path=images_dir,
annotations_path=annotations_path,
)
assert mock_tqdm.call_args[1]["disable"] is True
assert len(ds) == 3
@patch(_COCO_TQDM, wraps=_real_tqdm)
def test_from_coco_with_progress(
self, mock_tqdm: object, coco_dir: tuple[str, str]
):
"""COCO load shows progress bar when show_progress=True."""
images_dir, annotations_path = coco_dir
ds = DetectionDataset.from_coco(
images_directory_path=images_dir,
annotations_path=annotations_path,
show_progress=True,
)
assert mock_tqdm.call_args[1]["disable"] is False
assert len(ds) == 3
@patch(_COCO_TQDM, wraps=_real_tqdm)
def test_as_coco_with_progress(
self, mock_tqdm: object, coco_dataset: DetectionDataset, tmp_path: Path
):
"""COCO save shows progress bar when show_progress=True."""
out = tmp_path / "output"
coco_dataset.as_coco(
images_directory_path=str(out / "images"),
annotations_path=str(out / "annotations.json"),
show_progress=True,
)
assert mock_tqdm.call_args[1]["disable"] is False
@patch(_COCO_TQDM, wraps=_real_tqdm)
def test_as_coco_no_progress_by_default(
self, mock_tqdm: object, coco_dataset: DetectionDataset, tmp_path: Path
):
"""Saving COCO annotations does not show progress bar by default."""
coco_dataset.as_coco(
annotations_path=str(tmp_path / "output" / "annotations.json")
)
assert mock_tqdm.call_args[1]["disable"] is True
class TestPascalVocProgress:
@patch(_PASCAL_TQDM, wraps=_real_tqdm)
def test_from_pascal_voc_no_progress_by_default(
self, mock_tqdm: object, pascal_voc_dir: tuple[str, str]
):
"""Pascal VOC load does not show progress bar by default."""
images_dir, annotations_dir = pascal_voc_dir
ds = DetectionDataset.from_pascal_voc(
images_directory_path=images_dir,
annotations_directory_path=annotations_dir,
)
assert mock_tqdm.call_args[1]["disable"] is True
assert len(ds) == 3
@patch(_PASCAL_TQDM, wraps=_real_tqdm)
def test_from_pascal_voc_with_progress(
self, mock_tqdm: object, pascal_voc_dir: tuple[str, str]
):
"""Pascal VOC load shows progress bar when show_progress=True."""
images_dir, annotations_dir = pascal_voc_dir
ds = DetectionDataset.from_pascal_voc(
images_directory_path=images_dir,
annotations_directory_path=annotations_dir,
show_progress=True,
)
assert mock_tqdm.call_args[1]["disable"] is False
assert len(ds) == 3
def test_as_pascal_voc_with_progress(
self, pascal_voc_dataset: DetectionDataset, tmp_path: Path
):
"""Pascal VOC save shows progress bar when show_progress=True."""
out = tmp_path / "output"
with (
patch(_PASCAL_TQDM, wraps=_real_tqdm) as mock_tqdm,
patch(_UTILS_TQDM, wraps=_real_tqdm),
):
pascal_voc_dataset.as_pascal_voc(
images_directory_path=str(out / "images"),
annotations_directory_path=str(out / "annotations"),
show_progress=True,
)
assert mock_tqdm.call_args[1]["disable"] is False
@patch(_PASCAL_TQDM, wraps=_real_tqdm)
def test_as_pascal_voc_no_progress_by_default(
self, mock_tqdm: object, pascal_voc_dataset: DetectionDataset, tmp_path: Path
):
"""Saving Pascal VOC annotations does not show progress bar by default."""
pascal_voc_dataset.as_pascal_voc(
annotations_directory_path=str(tmp_path / "output" / "annotations")
)
assert mock_tqdm.call_args[1]["disable"] is True
class TestSaveImagesProgress:
@patch(_UTILS_TQDM, wraps=_real_tqdm)
def test_save_images_with_progress(
self, mock_tqdm: object, yolo_dataset: DetectionDataset, tmp_path: Path
):
"""save_dataset_images shows progress bar when show_progress=True."""
from supervision.dataset.utils import save_dataset_images
out_images = str(tmp_path / "output_images")
save_dataset_images(
dataset=yolo_dataset,
images_directory_path=out_images,
show_progress=True,
)
assert mock_tqdm.call_args[1]["disable"] is False
assert len(os.listdir(out_images)) == 3
@patch(_UTILS_TQDM, wraps=_real_tqdm)
def test_save_dataset_images_no_progress_by_default(
self, mock_tqdm: object, yolo_dataset: DetectionDataset, tmp_path: Path
):
"""save_dataset_images does not show progress bar by default."""
from supervision.dataset.utils import save_dataset_images
save_dataset_images(
dataset=yolo_dataset,
images_directory_path=str(tmp_path / "output_images_default"),
)
assert mock_tqdm.call_args[1]["disable"] is True
class TestBackwardCompatibility:
"""Ensure show_progress=False (default) doesn't change behavior."""
def test_from_yolo_default_works(self, yolo_dataset: DetectionDataset):
"""YOLO load with default args returns correct dataset size."""
assert len(yolo_dataset) == 3
def test_from_coco_default_works(self, coco_dataset: DetectionDataset):
"""COCO load with default args returns correct dataset size."""
assert len(coco_dataset) == 3
def test_from_pascal_voc_default_works(self, pascal_voc_dataset: DetectionDataset):
"""Pascal VOC load with default args returns correct dataset size."""
assert len(pascal_voc_dataset) == 3