Files
cvat-ai--cvat/tests/python/rest_api/_test_base.py
T
2026-07-13 13:32:23 +08:00

906 lines
33 KiB
Python

import io
import math
import os
from collections.abc import Mapping, Sequence
from functools import partial
from typing import IO
import numpy as np
import pytest
from attrs.converters import to_bool
from cvat_sdk.api_client import models
from PIL import Image
from pytest_cases import fixture, fixture_ref, parametrize
import shared.utils.s3 as s3
from rest_api.utils import calc_end_frame, create_task, iter_exclude, unique
from shared.fixtures.init import container_exec_cvat
from shared.tasks.enums import SourceDataType
from shared.tasks.interface import ITaskSpec
from shared.tasks.types import ImagesTaskSpec, VideoTaskSpec
from shared.tasks.utils import parse_frame_step
from shared.utils.config import SHARE_DIR, make_api_client
from shared.utils.helpers import generate_image_files, generate_video_file
def read_share_file(path: str) -> io.BytesIO:
data = io.BytesIO((SHARE_DIR / path).read_bytes())
data.name = path
return data
class TestTasksBase:
_USERNAME = "admin1"
def _image_task_fxt_base(
self,
request: pytest.FixtureRequest,
*,
frame_count: int | None = 10,
image_files: Sequence[io.BytesIO] | None = None,
related_files: Mapping[int, Sequence[io.BytesIO]] | None = None,
start_frame: int | None = None,
stop_frame: int | None = None,
step: int | None = None,
segment_size: int | None = None,
server_files: Sequence[str] | None = None,
cloud_storage_id: int | None = None,
job_replication: int | None = None,
**data_kwargs,
) -> tuple[ImagesTaskSpec, int]:
task_params = {
"name": f"{request.node.name}[{request.fixturename}]",
"labels": [{"name": "a"}],
**({"segment_size": segment_size} if segment_size else {}),
**({"consensus_replicas": job_replication} if job_replication else {}),
}
if server_files is not None:
assert (
image_files is not None
), "'server_files' must be used together with 'image_files'"
else:
assert bool(image_files) ^ bool(
frame_count
), "Expected only one of 'image_files' and 'frame_count'"
if not image_files:
image_files = generate_image_files(frame_count)
images_data = [f.getvalue() for f in image_files]
resulting_task_size = len(
range(start_frame or 0, (stop_frame or len(images_data) - 1) + 1, step or 1)
)
data_params = {
"image_quality": 70,
"sorting_method": "natural",
"chunk_size": max(1, (segment_size or resulting_task_size) // 2),
**(
{
"server_files": server_files,
"cloud_storage_id": cloud_storage_id,
}
if server_files
else {"client_files": image_files}
),
}
data_params.update(data_kwargs)
if start_frame is not None:
data_params["start_frame"] = start_frame
if stop_frame is not None:
data_params["stop_frame"] = stop_frame
if step is not None:
data_params["frame_filter"] = f"step={step}"
def get_frame(i: int) -> bytes:
return images_data[i]
if related_files is not None:
def get_related_files(i: int) -> Mapping[str, bytes]:
frame_ri = related_files.get(i)
common_prefix = ""
if frame_ri:
common_prefix = os.path.commonpath(os.path.dirname(f.name) for f in frame_ri)
return {os.path.relpath(f.name, common_prefix): f.getvalue() for f in frame_ri}
task_id, _ = create_task(self._USERNAME, spec=task_params, data=data_params)
return (
ImagesTaskSpec(
models.TaskWriteRequest._from_openapi_data(**task_params),
models.DataRequest._from_openapi_data(**data_params),
get_frame=get_frame,
get_related_files=get_related_files if related_files else None,
size=resulting_task_size,
),
task_id,
)
@pytest.fixture(scope="class")
def fxt_uploaded_images_task(self, request: pytest.FixtureRequest) -> tuple[ITaskSpec, int]:
return self._image_task_fxt_base(request=request)
@pytest.fixture(scope="class")
def fxt_uploaded_images_task_with_segments(
self, request: pytest.FixtureRequest
) -> tuple[ITaskSpec, int]:
return self._image_task_fxt_base(request=request, segment_size=4)
@fixture(scope="class")
@parametrize("step", [2, 5])
@parametrize("stop_frame", [15, 26])
@parametrize("start_frame", [3, 7])
def fxt_uploaded_images_task_with_segments_start_stop_step(
self, request: pytest.FixtureRequest, start_frame: int, stop_frame: int | None, step: int
) -> tuple[ITaskSpec, int]:
return self._image_task_fxt_base(
request=request,
frame_count=30,
segment_size=4,
start_frame=start_frame,
stop_frame=stop_frame,
step=step,
)
@pytest.fixture(scope="class")
def fxt_uploaded_images_task_with_segments_and_consensus(
self, request: pytest.FixtureRequest
) -> tuple[ITaskSpec, int]:
return self._image_task_fxt_base(request=request, segment_size=4, job_replication=2)
def _image_task_with_honeypots_and_segments_base(
self,
request: pytest.FixtureRequest,
*,
start_frame: int | None = None,
step: int | None = None,
random_seed: int = 42,
image_files: Sequence[io.BytesIO] | None = None,
server_files: Sequence[str] | None = None,
cloud_storage_id: int | None = None,
**kwargs,
) -> tuple[ITaskSpec, int]:
validation_params = models.DataRequestValidationParams._from_openapi_data(
mode="gt_pool",
frame_selection_method="random_uniform",
random_seed=random_seed,
frame_count=5,
frames_per_job_count=2,
)
used_frames_count = 15
total_frame_count = (start_frame or 0) + used_frames_count * (step or 1)
base_segment_size = 4
regular_frame_count = used_frames_count - validation_params.frame_count
final_segment_size = base_segment_size + validation_params.frames_per_job_count
final_task_size = (
regular_frame_count
+ validation_params.frames_per_job_count
* math.ceil(regular_frame_count / base_segment_size)
+ validation_params.frame_count
)
if image_files:
if len(image_files) != total_frame_count:
raise ValueError(
f"If provided, image_files must contain {total_frame_count} images"
)
else:
image_files = generate_image_files(total_frame_count)
task_spec, task_id = self._image_task_fxt_base(
request=request,
frame_count=None,
image_files=image_files,
segment_size=base_segment_size,
sorting_method="random",
start_frame=start_frame,
step=step,
validation_params=validation_params,
server_files=server_files,
cloud_storage_id=cloud_storage_id,
**kwargs,
)
# Get the actual frame order after the task is created
with make_api_client(self._USERNAME) as api_client:
task_meta, _ = api_client.tasks_api.retrieve_data_meta(task_id)
frame_map = [
next(i for i, f in enumerate(image_files) if f.name == frame_info.name)
for frame_info in task_meta.frames
]
_get_frame = task_spec._get_frame
task_spec._get_frame = lambda i: _get_frame(frame_map[i])
task_spec.size = final_task_size
task_spec._params.segment_size = final_segment_size
# These parameters are not applicable to the resulting task,
# they are only effective during task creation
if start_frame or step:
task_spec._data_params.start_frame = 0
task_spec._data_params.stop_frame = task_spec.size
task_spec._data_params.frame_filter = ""
return task_spec, task_id
@fixture(scope="class")
def fxt_uploaded_images_task_with_honeypots_and_segments(
self, request: pytest.FixtureRequest
) -> tuple[ITaskSpec, int]:
return self._image_task_with_honeypots_and_segments_base(request)
@fixture(scope="class")
@parametrize("start_frame, step", [(2, 3)])
def fxt_uploaded_images_task_with_honeypots_and_segments_start_step(
self, request: pytest.FixtureRequest, start_frame: int | None, step: int | None
) -> tuple[ITaskSpec, int]:
return self._image_task_with_honeypots_and_segments_base(
request, start_frame=start_frame, step=step
)
def _images_task_with_honeypots_and_changed_real_frames_base(
self, request: pytest.FixtureRequest, **kwargs
):
task_spec, task_id = self._image_task_with_honeypots_and_segments_base(
request, start_frame=2, step=3, **kwargs
)
with make_api_client(self._USERNAME) as api_client:
validation_layout, _ = api_client.tasks_api.retrieve_validation_layout(task_id)
validation_frames = validation_layout.validation_frames
new_honeypot_real_frames = [
validation_frames[(validation_frames.index(f) + 1) % len(validation_frames)]
for f in validation_layout.honeypot_real_frames
]
api_client.tasks_api.partial_update_validation_layout(
task_id,
patched_task_validation_layout_write_request=(
models.PatchedTaskValidationLayoutWriteRequest(
frame_selection_method="manual",
honeypot_real_frames=new_honeypot_real_frames,
)
),
)
# Get the new frame order
frame_map = dict(zip(validation_layout.honeypot_frames, new_honeypot_real_frames))
_get_frame = task_spec._get_frame
task_spec._get_frame = lambda i: _get_frame(frame_map.get(i, i))
return task_spec, task_id
@fixture(scope="class")
@parametrize("random_seed", [1, 2, 5])
def fxt_uploaded_images_task_with_honeypots_and_changed_real_frames(
self, request: pytest.FixtureRequest, random_seed: int
) -> tuple[ITaskSpec, int]:
return self._images_task_with_honeypots_and_changed_real_frames_base(
request, random_seed=random_seed
)
@fixture(scope="class")
@parametrize(
"cloud_storage_id",
[pytest.param(2, marks=[pytest.mark.with_external_services, pytest.mark.timeout(60)])],
)
def fxt_cloud_images_task_with_honeypots_and_changed_real_frames(
self, request: pytest.FixtureRequest, cloud_storages, cloud_storage_id: int
) -> tuple[ITaskSpec, int]:
cloud_storage = cloud_storages[cloud_storage_id]
s3_client = s3.make_client(bucket=cloud_storage["resource"])
image_files = generate_image_files(47)
for image in image_files:
image.name = f"test/{image.name}"
image.seek(0)
s3_client.create_file(data=image, filename=image.name)
request.addfinalizer(partial(s3_client.remove_file, filename=image.name))
server_files = [f.name for f in image_files]
for image in image_files:
image.seek(0)
return self._images_task_with_honeypots_and_changed_real_frames_base(
request,
image_files=image_files,
server_files=server_files,
cloud_storage_id=cloud_storage_id,
# FIXME: random sorting with frame filter and cloud images (and, optionally, honeypots)
# doesn't work with static cache
# https://github.com/cvat-ai/cvat/issues/9021
use_cache=True,
)
def _uploaded_images_task_with_gt_and_segments_base(
self,
request: pytest.FixtureRequest,
*,
start_frame: int | None = None,
step: int | None = None,
frame_selection_method: str = "random_uniform",
job_replication: int | None = None,
) -> tuple[ITaskSpec, int]:
used_frames_count = 16
total_frame_count = (start_frame or 0) + used_frames_count * (step or 1)
segment_size = 5
image_files = generate_image_files(total_frame_count)
validation_params_kwargs = {"frame_selection_method": frame_selection_method}
if "random" in frame_selection_method:
validation_params_kwargs["random_seed"] = 42
if frame_selection_method == "random_uniform":
validation_frames_count = 10
validation_params_kwargs["frame_count"] = validation_frames_count
elif frame_selection_method == "random_per_job":
frames_per_job_count = 3
validation_params_kwargs["frames_per_job_count"] = frames_per_job_count
validation_frames_count = used_frames_count // segment_size + min(
used_frames_count % segment_size, frames_per_job_count
)
elif frame_selection_method == "manual":
validation_frames_count = 10
valid_frame_ids = range(
(start_frame or 0), (start_frame or 0) + used_frames_count * (step or 1), step or 1
)
rng = np.random.Generator(np.random.MT19937(seed=42))
validation_params_kwargs["frames"] = rng.choice(
[f.name for i, f in enumerate(image_files) if i in valid_frame_ids],
validation_frames_count,
replace=False,
).tolist()
else:
raise NotImplementedError
validation_params = models.DataRequestValidationParams._from_openapi_data(
mode="gt",
**validation_params_kwargs,
)
return self._image_task_fxt_base(
request=request,
frame_count=None,
image_files=image_files,
segment_size=segment_size,
sorting_method="natural",
start_frame=start_frame,
step=step,
validation_params=validation_params,
job_replication=job_replication,
)
@pytest.fixture(scope="class")
def fxt_uploaded_images_task_with_gt_and_segments_and_consensus(
self, request: pytest.FixtureRequest
) -> tuple[ITaskSpec, int]:
return self._uploaded_images_task_with_gt_and_segments_base(
request=request, job_replication=2
)
@fixture(scope="class")
@parametrize(
"cloud_storage_id",
[
pytest.param(
1,
marks=[
pytest.mark.with_external_services,
pytest.mark.timeout(60),
pytest.mark.xfail(
to_bool(os.getenv("CVAT_ALLOW_STATIC_CACHE", False)),
reason="Creating a task from a cloud .bin file with static cache doesn't work at the moment",
),
],
)
],
)
def fxt_cloud_bin_pointcloud_task(
self, request: pytest.FixtureRequest, cloud_storages, cloud_storage_id: int
) -> tuple[ITaskSpec, int]:
cloud_storage = cloud_storages[cloud_storage_id]
s3_client = s3.make_client(bucket=cloud_storage["resource"])
server_files = ["bin_pointcloud/000002.bin"]
bin_files = []
for filename in server_files:
bin_file = io.BytesIO(s3_client.download_fileobj(filename))
bin_file.name = filename
bin_files.append(bin_file)
return self._image_task_fxt_base(
request,
image_files=bin_files,
server_files=server_files,
cloud_storage_id=cloud_storage_id,
)
@fixture(scope="class")
@parametrize(
"cloud_storage_id",
[pytest.param(2, marks=[pytest.mark.with_external_services, pytest.mark.timeout(60)])],
)
def fxt_cloud_images_task_with_related_images(
self, request: pytest.FixtureRequest, cloud_storages, cloud_storage_id: int
) -> tuple[ITaskSpec, int]:
cloud_storage = cloud_storages[cloud_storage_id]
s3_client = s3.make_client(bucket=cloud_storage["resource"])
image_files = generate_image_files(5)
def _upload_file(file: io.RawIOBase):
s3_client.create_file(data=file, filename=file.name)
request.addfinalizer(partial(s3_client.remove_file, filename=file.name))
related_files = []
for i, image in enumerate(image_files):
image.name = f"test/{image.name}"
image.seek(0)
_upload_file(image)
image_related_files = generate_image_files(i)
related_files.append(image_related_files)
for related_file in image_related_files:
assert related_file.name.endswith(".jpeg")
related_file.name = "{}/related_images/{}/{}".format(
os.path.dirname(image.name),
os.path.basename(image.name).replace(".", "_"),
related_file.name,
)
related_file.seek(0)
_upload_file(related_file)
server_files = [f.name for f in image_files] + [
f.name for rfs in related_files for f in rfs
]
for image in image_files:
image.seek(0)
return self._image_task_fxt_base(
request,
image_files=image_files,
related_files=dict(enumerate(related_files)),
server_files=server_files,
cloud_storage_id=cloud_storage_id,
)
@fixture(scope="class")
@parametrize(
"cloud_storage_id",
[pytest.param(1, marks=[pytest.mark.with_external_services, pytest.mark.timeout(60)])],
)
def fxt_cloud_pcd_task_with_related_images(
self, request: pytest.FixtureRequest, cloud_storages, cloud_storage_id: int
) -> tuple[ITaskSpec, int]:
cloud_storage = cloud_storages[cloud_storage_id]
s3_client = s3.make_client(bucket=cloud_storage["resource"])
server_files = [
"pcd_with_related/pointcloud/000001.pcd",
"pcd_with_related/pointcloud/000002.pcd",
"pcd_with_related/pointcloud/000003.pcd",
"pcd_with_related/related_images/000001_pcd/000001.png",
"pcd_with_related/related_images/000002_pcd/000002.png",
"pcd_with_related/related_images/000003_pcd/000003.png",
]
pcd_files = []
for filename in [
"pcd_with_related/pointcloud/000001.pcd",
"pcd_with_related/pointcloud/000002.pcd",
"pcd_with_related/pointcloud/000003.pcd",
]:
pcd_file = io.BytesIO(s3_client.download_fileobj(filename))
pcd_file.name = filename
pcd_files.append(pcd_file)
related_files = []
for filename in [
"pcd_with_related/related_images/000001_pcd/000001.png",
"pcd_with_related/related_images/000002_pcd/000002.png",
"pcd_with_related/related_images/000003_pcd/000003.png",
]:
ri_file = io.BytesIO(s3_client.download_fileobj(filename))
ri_file.name = os.path.basename(filename)
related_files.append([ri_file])
return self._image_task_fxt_base(
request,
image_files=pcd_files,
related_files=dict(enumerate(related_files)),
server_files=server_files,
cloud_storage_id=cloud_storage_id,
)
def _share_images_task_with_related_images(
self,
request: pytest.FixtureRequest,
**data_kwargs,
) -> tuple[ITaskSpec, int]:
image_files = [
read_share_file(fn)
for fn in [
"images/with_related/image_0.png",
"images/with_related/image_1.png",
"images/with_related/image_2.png",
"images/with_related/image_3.png",
]
]
related_files = {
0: [
"images/with_related/related_images/image_0_png/30.png",
"images/with_related/related_images/image_0_png/31.png",
"images/with_related/related_images/image_0_png/33.png",
],
1: [
"images/with_related/related_images/image_1_png/30.png",
],
2: [
"images/with_related/related_images/image_2_png/32.png",
"images/with_related/related_images/image_2_png/33.png",
"images/with_related/related_images/image_2_png/34.png",
],
3: [],
}
for k, fs in related_files.items():
related_files[k] = [read_share_file(fn) for fn in fs]
server_files = [f.name for f in image_files] + [
f.name for fs in related_files.values() for f in fs
]
return self._image_task_fxt_base(
request,
image_files=image_files,
related_files=related_files,
server_files=server_files,
**data_kwargs,
)
@fixture(scope="class")
def fxt_share_images_task_with_related_images(
self, request: pytest.FixtureRequest
) -> tuple[ITaskSpec, int]:
return self._share_images_task_with_related_images(request)
@fixture(scope="class")
@parametrize(
"cloud_storage_id",
[pytest.param(5, marks=[pytest.mark.with_external_services])],
)
def fxt_backing_cs_images_task_with_related_images(
self, request: pytest.FixtureRequest, cloud_storage_id: int
) -> tuple[ITaskSpec, int]:
# The simplest way to get a task with local storage and subdirectories is to use the share
# with copy_data.
task_spec, task_id = self._share_images_task_with_related_images(
request, copy_data=True, use_cache=True
)
container_exec_cvat(
request, ["./manage.py", "movetasktobackingcs", str(task_id), str(cloud_storage_id)]
)
return task_spec, task_id
@fixture(scope="class")
def fxt_share_pcd_task_with_related_images(
self,
request: pytest.FixtureRequest,
) -> tuple[ITaskSpec, int]:
pcd_files = [
read_share_file(fn)
for fn in [
"pcd_with_related/pointcloud/000001.pcd",
"pcd_with_related/pointcloud/000002.pcd",
"pcd_with_related/pointcloud/000003.pcd",
]
]
related_files = {
0: [
"pcd_with_related/related_images/000001_pcd/000001.png",
],
1: [
"pcd_with_related/related_images/000002_pcd/000002.png",
],
2: [
"pcd_with_related/related_images/000003_pcd/000003.png",
],
3: [],
}
for k, fs in related_files.items():
related_files[k] = [read_share_file(fn) for fn in fs]
server_files = [f.name for f in pcd_files] + [
f.name for fs in related_files.values() for f in fs
]
return self._image_task_fxt_base(
request,
image_files=pcd_files,
related_files=related_files,
server_files=server_files,
)
@fixture(scope="class")
@parametrize("start_frame, step", [(2, 3)])
@parametrize("frame_selection_method", ["random_uniform", "random_per_job", "manual"])
def fxt_uploaded_images_task_with_gt_and_segments_start_step(
self,
request: pytest.FixtureRequest,
start_frame: int | None,
step: int | None,
frame_selection_method: str,
) -> tuple[ITaskSpec, int]:
return self._uploaded_images_task_with_gt_and_segments_base(
request,
start_frame=start_frame,
step=step,
frame_selection_method=frame_selection_method,
)
def _uploaded_video_task_fxt_base(
self,
request: pytest.FixtureRequest,
*,
frame_count: int = 10,
segment_size: int | None = None,
start_frame: int | None = None,
stop_frame: int | None = None,
step: int | None = None,
video_file: IO[bytes] | None = None,
chapters: Sequence[dict] | None = None,
) -> tuple[VideoTaskSpec, int]:
task_params = {
"name": f"{request.node.name}[{request.fixturename}]",
"labels": [{"name": "a"}],
}
if segment_size:
task_params["segment_size"] = segment_size
resulting_task_size = len(
range(start_frame or 0, (stop_frame or frame_count - 1) + 1, step or 1)
)
assert (not video_file) ^ (
chapters is not None
), "Chapters must be specified with a custom video file"
if not video_file:
video_file = generate_video_file(frame_count)
video_data = video_file.getvalue()
chapters = [
{
"start": 0,
"stop": 5,
"metadata": {"title": "Intro"},
}
]
else:
video_data = video_file.read()
video_file.seek(0)
data_params = {
"image_quality": 70,
"client_files": [video_file],
"chunk_size": max(1, (segment_size or resulting_task_size) // 2),
}
if start_frame is not None:
data_params["start_frame"] = start_frame
if stop_frame is not None:
data_params["stop_frame"] = stop_frame
if step is not None:
data_params["frame_filter"] = f"step={step}"
def get_video_file() -> io.BytesIO:
return io.BytesIO(video_data)
task_id, _ = create_task(self._USERNAME, spec=task_params, data=data_params)
return (
VideoTaskSpec(
models.TaskWriteRequest._from_openapi_data(**task_params),
models.DataRequest._from_openapi_data(**data_params),
get_video_file=get_video_file,
size=resulting_task_size,
chapters=chapters,
),
task_id,
)
@pytest.fixture(scope="class")
def fxt_uploaded_video_task(
self,
request: pytest.FixtureRequest,
) -> tuple[ITaskSpec, int]:
return self._uploaded_video_task_fxt_base(request=request)
@pytest.fixture(scope="class")
def fxt_uploaded_video_task_without_manifest(
self,
request: pytest.FixtureRequest,
) -> tuple[ITaskSpec, int]:
video_file = generate_video_file(num_frames=10, invalid_keyframes=True)
return self._uploaded_video_task_fxt_base(
request=request, video_file=video_file, chapters=[]
)
@pytest.fixture(scope="class")
def fxt_uploaded_video_task_with_segments(
self, request: pytest.FixtureRequest
) -> tuple[ITaskSpec, int]:
return self._uploaded_video_task_fxt_base(request=request, segment_size=4)
@fixture(scope="class")
@parametrize("step", [2, 5])
@parametrize("stop_frame", [15, 26])
@parametrize("start_frame", [3, 7])
def fxt_uploaded_video_task_with_segments_start_stop_step(
self, request: pytest.FixtureRequest, start_frame: int, stop_frame: int | None, step: int
) -> tuple[ITaskSpec, int]:
return self._uploaded_video_task_fxt_base(
request=request,
frame_count=30,
segment_size=4,
start_frame=start_frame,
stop_frame=stop_frame,
step=step,
)
def _compute_annotation_segment_params(self, task_spec: ITaskSpec) -> list[tuple[int, int]]:
segment_params = []
frame_step = task_spec.frame_step
segment_size = getattr(task_spec, "segment_size", 0) or task_spec.size * frame_step
start_frame = getattr(task_spec, "start_frame", 0)
stop_frame = getattr(task_spec, "stop_frame", None) or (
start_frame + (task_spec.size - 1) * frame_step
)
end_frame = calc_end_frame(start_frame, stop_frame, frame_step)
validation_params = getattr(task_spec, "validation_params", None)
if validation_params and validation_params.mode.value == "gt_pool":
end_frame = min(
end_frame, (task_spec.size - validation_params.frame_count) * frame_step
)
segment_size = min(segment_size, end_frame - 1)
overlap = min(
(
getattr(task_spec, "overlap", None) or 0
if task_spec.source_data_type == SourceDataType.images
else 5
),
segment_size // 2,
)
segment_start = start_frame
while segment_start < end_frame:
if start_frame < segment_start:
segment_start -= overlap * frame_step
segment_end = segment_start + frame_step * segment_size
segment_params.append((segment_start, min(segment_end, end_frame) - frame_step))
segment_start = segment_end
return segment_params
@staticmethod
def _compare_images(
expected: Image.Image, actual: Image.Image, *, must_be_identical: bool = True
):
expected_pixels = np.array(expected)
actual_pixels = np.array(actual)
assert expected_pixels.shape == actual_pixels.shape
if not must_be_identical:
# video chunks can have slightly changed colors, due to codec specifics
# compressed images can also be distorted
assert np.allclose(actual_pixels, expected_pixels, atol=3)
else:
assert np.array_equal(actual_pixels, expected_pixels)
def _get_job_abs_frame_set(self, job_meta: models.DataMetaRead) -> Sequence[int]:
if job_meta.included_frames:
return job_meta.included_frames
else:
return range(
job_meta.start_frame,
job_meta.stop_frame + 1,
parse_frame_step(job_meta.frame_filter),
)
_tasks_with_honeypots_cases = [
fixture_ref("fxt_uploaded_images_task_with_honeypots_and_segments"),
fixture_ref("fxt_uploaded_images_task_with_honeypots_and_segments_start_step"),
fixture_ref("fxt_uploaded_images_task_with_honeypots_and_changed_real_frames"),
fixture_ref("fxt_cloud_images_task_with_honeypots_and_changed_real_frames"),
]
_tasks_with_simple_gt_job_cases = [
fixture_ref("fxt_uploaded_images_task_with_gt_and_segments_start_step"),
fixture_ref("fxt_uploaded_images_task_with_gt_and_segments_and_consensus"),
]
_tasks_with_consensus_cases = [
fixture_ref("fxt_uploaded_images_task_with_segments_and_consensus"),
fixture_ref("fxt_uploaded_images_task_with_gt_and_segments_and_consensus"),
]
_tests_with_cloud_storage_cases = [
fixture_ref("fxt_cloud_bin_pointcloud_task"),
fixture_ref("fxt_cloud_images_task_with_honeypots_and_changed_real_frames"),
fixture_ref("fxt_cloud_images_task_with_related_images"),
]
_tests_with_share_cases = [
fixture_ref("fxt_share_images_task_with_related_images"),
fixture_ref("fxt_share_pcd_task_with_related_images"),
]
_tests_with_related_files_cases = [
fixture_ref("fxt_cloud_images_task_with_related_images"),
fixture_ref("fxt_cloud_pcd_task_with_related_images"),
fixture_ref("fxt_share_images_task_with_related_images"),
fixture_ref("fxt_share_pcd_task_with_related_images"),
fixture_ref("fxt_backing_cs_images_task_with_related_images"),
]
_3d_task_cases = [
fixture_ref("fxt_cloud_bin_pointcloud_task"),
fixture_ref("fxt_cloud_pcd_task_with_related_images"),
fixture_ref("fxt_share_pcd_task_with_related_images"),
]
# Keep in mind that these fixtures are generated eagerly
# (before each depending test or group of tests),
# e.g. a failing task creation in one the fixtures will fail all the depending tests cases.
_all_task_cases = unique(
[
fixture_ref("fxt_uploaded_images_task"),
fixture_ref("fxt_uploaded_images_task_with_segments"),
fixture_ref("fxt_uploaded_images_task_with_segments_start_stop_step"),
fixture_ref("fxt_uploaded_video_task"),
fixture_ref("fxt_uploaded_video_task_without_manifest"),
fixture_ref("fxt_uploaded_video_task_with_segments"),
fixture_ref("fxt_uploaded_video_task_with_segments_start_stop_step"),
]
+ _tasks_with_honeypots_cases
+ _tasks_with_simple_gt_job_cases
+ _tasks_with_consensus_cases
+ _tests_with_cloud_storage_cases
+ _tests_with_related_files_cases
+ _tests_with_share_cases,
key=lambda fxt_ref: fxt_ref.fixture,
)
_2d_task_cases = list(
iter_exclude(
_all_task_cases,
excludes=set(v.fixture for v in _3d_task_cases),
key=lambda v: v.fixture,
)
)