|
|
|
|
@ -199,6 +199,11 @@ class _DbTestBase(APITestCase):
|
|
|
|
|
response = self.client.put(path, data)
|
|
|
|
|
return response
|
|
|
|
|
|
|
|
|
|
def _post_request_with_data(self, path, data, user):
|
|
|
|
|
with ForceLogin(user, self.client):
|
|
|
|
|
response = self.client.post(path, data)
|
|
|
|
|
return response
|
|
|
|
|
|
|
|
|
|
def _delete_request(self, path, user):
|
|
|
|
|
with ForceLogin(user, self.client):
|
|
|
|
|
response = self.client.delete(path)
|
|
|
|
|
@ -349,6 +354,9 @@ class _DbTestBase(APITestCase):
|
|
|
|
|
def _generate_url_dump_project_dataset(self, project_id, format_name):
|
|
|
|
|
return f"/api/projects/{project_id}/dataset?format={format_name}"
|
|
|
|
|
|
|
|
|
|
def _generate_url_upload_project_dataset(self, project_id, format_name):
|
|
|
|
|
return f"/api/projects/{project_id}/dataset?format={format_name}"
|
|
|
|
|
|
|
|
|
|
def _remove_annotations(self, url, user):
|
|
|
|
|
response = self._delete_request(url, user)
|
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
|
|
|
|
|
@ -436,7 +444,6 @@ class TaskDumpUploadTest(_DbTestBase):
|
|
|
|
|
if upload_format_name == "CVAT 1.1":
|
|
|
|
|
file_zip_name = osp.join(test_dir, f'{test_name}_admin_CVAT for images 1.1.zip')
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
|
|
file_zip_name = osp.join(test_dir, f'{test_name}_admin_{upload_format_name}.zip')
|
|
|
|
|
if not upload_format.ENABLED or not osp.exists(file_zip_name):
|
|
|
|
|
continue
|
|
|
|
|
@ -925,21 +932,20 @@ class TaskDumpUploadTest(_DbTestBase):
|
|
|
|
|
dump_formats = dm.views.get_export_formats()
|
|
|
|
|
with TestDir() as test_dir:
|
|
|
|
|
for dump_format in dump_formats:
|
|
|
|
|
if not dump_format.ENABLED:
|
|
|
|
|
if not dump_format.ENABLED or dump_format.DIMENSION == dm.bindings.DimensionType.DIM_3D:
|
|
|
|
|
continue
|
|
|
|
|
dump_format_name = dump_format.DISPLAY_NAME
|
|
|
|
|
|
|
|
|
|
with self.subTest(format=dump_format_name):
|
|
|
|
|
if dump_format_name in [
|
|
|
|
|
"MOTS PNG 1.0", # issue #2925 and changed points values
|
|
|
|
|
'Kitti Raw Format 1.0',
|
|
|
|
|
'Sly Point Cloud Format 1.0',
|
|
|
|
|
'Datumaro 3D 1.0',
|
|
|
|
|
"Cityscapes 1.0" # expanding annotations due to background mask
|
|
|
|
|
]:
|
|
|
|
|
self.skipTest("Format is fail")
|
|
|
|
|
|
|
|
|
|
images = self._generate_task_images(3)
|
|
|
|
|
if dump_format_name in [
|
|
|
|
|
"Market-1501 1.0", "Cityscapes 1.0", \
|
|
|
|
|
"Market-1501 1.0",
|
|
|
|
|
"ICDAR Localization 1.0", "ICDAR Recognition 1.0", \
|
|
|
|
|
"ICDAR Segmentation 1.0", "COCO Keypoints 1.0",
|
|
|
|
|
]:
|
|
|
|
|
@ -947,11 +953,11 @@ class TaskDumpUploadTest(_DbTestBase):
|
|
|
|
|
else:
|
|
|
|
|
task = self._create_task(tasks["main"], images)
|
|
|
|
|
task_id = task["id"]
|
|
|
|
|
|
|
|
|
|
if dump_format_name in [
|
|
|
|
|
"MOT 1.1", "MOTS PNG 1.0",
|
|
|
|
|
"PASCAL VOC 1.1", "Segmentation mask 1.1",
|
|
|
|
|
"MOT 1.1", "PASCAL VOC 1.1", "Segmentation mask 1.1",
|
|
|
|
|
"TFRecord 1.0", "YOLO 1.1", "ImageNet 1.0",
|
|
|
|
|
"WiderFace 1.0", "VGGFace2 1.0", "Cityscapes 1.0",
|
|
|
|
|
"WiderFace 1.0", "VGGFace2 1.0",
|
|
|
|
|
"Datumaro 1.0", "Open Images V6 1.0", "KITTI 1.0"
|
|
|
|
|
]:
|
|
|
|
|
self._create_annotations(task, dump_format_name, "default")
|
|
|
|
|
@ -981,6 +987,7 @@ class TaskDumpUploadTest(_DbTestBase):
|
|
|
|
|
|
|
|
|
|
with open(file_zip_name, 'rb') as binary_file:
|
|
|
|
|
self._upload_file(url, binary_file, self.admin)
|
|
|
|
|
|
|
|
|
|
task_ann = TaskAnnotation(task_id)
|
|
|
|
|
task_ann.init_from_db()
|
|
|
|
|
task_ann_data = task_ann.data
|
|
|
|
|
@ -1209,10 +1216,11 @@ class TaskDumpUploadTest(_DbTestBase):
|
|
|
|
|
data_from_task_after_upload = self._get_data_from_task(task_id, include_images)
|
|
|
|
|
compare_datasets(self, data_from_task_before_upload, data_from_task_after_upload)
|
|
|
|
|
|
|
|
|
|
class ProjectDump(_DbTestBase):
|
|
|
|
|
def test_api_v2_export_dataset(self):
|
|
|
|
|
class ProjectDumpUpload(_DbTestBase):
|
|
|
|
|
def test_api_v2_export_import_dataset(self):
|
|
|
|
|
test_name = self._testMethodName
|
|
|
|
|
dump_formats = dm.views.get_export_formats()
|
|
|
|
|
upload_formats = dm.views.get_import_formats()
|
|
|
|
|
|
|
|
|
|
expected = {
|
|
|
|
|
self.admin: {'name': 'admin', 'code': status.HTTP_200_OK, 'create code': status.HTTP_201_CREATED,
|
|
|
|
|
@ -1228,41 +1236,83 @@ class ProjectDump(_DbTestBase):
|
|
|
|
|
if not dump_format.ENABLED or dump_format.DIMENSION == dm.bindings.DimensionType.DIM_3D:
|
|
|
|
|
continue
|
|
|
|
|
dump_format_name = dump_format.DISPLAY_NAME
|
|
|
|
|
with self.subTest(format=dump_format_name):
|
|
|
|
|
project = self._create_project(projects['main'])
|
|
|
|
|
pid = project['id']
|
|
|
|
|
images = self._generate_task_images(3)
|
|
|
|
|
tasks['task in project #1']['project_id'] = pid
|
|
|
|
|
self._create_task(tasks['task in project #1'], images)
|
|
|
|
|
images = self._generate_task_images(3, 3)
|
|
|
|
|
tasks['task in project #2']['project_id'] = pid
|
|
|
|
|
self._create_task(tasks['task in project #2'], images)
|
|
|
|
|
url = self._generate_url_dump_project_dataset(project['id'], dump_format_name)
|
|
|
|
|
if dump_format_name in [
|
|
|
|
|
'Cityscapes 1.0', 'LFW 1.0', 'Market-1501 1.0',
|
|
|
|
|
'MOT 1.1', 'TFRecord 1.0'
|
|
|
|
|
]:
|
|
|
|
|
# TO-DO: fix bug for this formats
|
|
|
|
|
continue
|
|
|
|
|
project = copy.deepcopy(projects['main'])
|
|
|
|
|
if dump_format_name in tasks:
|
|
|
|
|
project['labels'] = tasks[dump_format_name]['labels']
|
|
|
|
|
project = self._create_project(project)
|
|
|
|
|
tasks['task in project #1']['project_id'] = project['id']
|
|
|
|
|
task = self._create_task(tasks['task in project #1'], self._generate_task_images(3))
|
|
|
|
|
|
|
|
|
|
url = self._generate_url_dump_project_dataset(project['id'], dump_format_name)
|
|
|
|
|
|
|
|
|
|
if dump_format_name in [
|
|
|
|
|
"Cityscapes 1.0", "Datumaro 1.0", "ImageNet 1.0",
|
|
|
|
|
"MOT 1.1", "MOTS PNG 1.0", "PASCAL VOC 1.1",
|
|
|
|
|
"Segmentation mask 1.1", "TFRecord 1.0", "VGGFace2 1.0",
|
|
|
|
|
"WiderFace 1.0", "YOLO 1.1"
|
|
|
|
|
]:
|
|
|
|
|
self._create_annotations(task, dump_format_name, "default")
|
|
|
|
|
else:
|
|
|
|
|
self._create_annotations(task, dump_format_name, "random")
|
|
|
|
|
|
|
|
|
|
for user, edata in list(expected.items()):
|
|
|
|
|
user_name = edata['name']
|
|
|
|
|
file_zip_name = osp.join(test_dir, f'{test_name}_{user_name}_{dump_format_name}.zip')
|
|
|
|
|
data = {
|
|
|
|
|
"format": dump_format_name,
|
|
|
|
|
}
|
|
|
|
|
response = self._get_request_with_data(url, data, user)
|
|
|
|
|
self.assertEqual(response.status_code, edata["accept code"])
|
|
|
|
|
response = self._get_request_with_data(url, data, user)
|
|
|
|
|
self.assertEqual(response.status_code, edata["create code"])
|
|
|
|
|
data = {
|
|
|
|
|
"format": dump_format_name,
|
|
|
|
|
"action": "download",
|
|
|
|
|
}
|
|
|
|
|
response = self._get_request_with_data(url, data, user)
|
|
|
|
|
self.assertEqual(response.status_code, edata["code"])
|
|
|
|
|
if response.status_code == status.HTTP_200_OK:
|
|
|
|
|
content = BytesIO(b"".join(response.streaming_content))
|
|
|
|
|
with open(file_zip_name, "wb") as f:
|
|
|
|
|
f.write(content.getvalue())
|
|
|
|
|
self.assertEqual(response.status_code, edata['code'])
|
|
|
|
|
self.assertEqual(osp.exists(file_zip_name), edata['file_exists'])
|
|
|
|
|
for user, edata in list(expected.items()):
|
|
|
|
|
user_name = edata['name']
|
|
|
|
|
file_zip_name = osp.join(test_dir, f'{test_name}_{user_name}_{dump_format_name}.zip')
|
|
|
|
|
data = {
|
|
|
|
|
"format": dump_format_name,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
response = self._get_request_with_data(url, data, user)
|
|
|
|
|
self.assertEqual(response.status_code, edata["accept code"])
|
|
|
|
|
|
|
|
|
|
response = self._get_request_with_data(url, data, user)
|
|
|
|
|
self.assertEqual(response.status_code, edata["create code"])
|
|
|
|
|
|
|
|
|
|
data = {
|
|
|
|
|
"format": dump_format_name,
|
|
|
|
|
"action": "download",
|
|
|
|
|
}
|
|
|
|
|
response = self._get_request_with_data(url, data, user)
|
|
|
|
|
self.assertEqual(response.status_code, edata["code"])
|
|
|
|
|
|
|
|
|
|
if response.status_code == status.HTTP_200_OK:
|
|
|
|
|
content = BytesIO(b"".join(response.streaming_content))
|
|
|
|
|
with open(file_zip_name, "wb") as f:
|
|
|
|
|
f.write(content.getvalue())
|
|
|
|
|
|
|
|
|
|
self.assertEqual(response.status_code, edata['code'])
|
|
|
|
|
self.assertEqual(osp.exists(file_zip_name), edata['file_exists'])
|
|
|
|
|
|
|
|
|
|
for upload_format in upload_formats:
|
|
|
|
|
if not upload_format.ENABLED or upload_format.DIMENSION == dm.bindings.DimensionType.DIM_3D:
|
|
|
|
|
continue
|
|
|
|
|
upload_format_name = upload_format.DISPLAY_NAME
|
|
|
|
|
if upload_format_name in [
|
|
|
|
|
'Cityscapes 1.0', 'LFW 1.0', 'Market-1501 1.0',
|
|
|
|
|
'MOT 1.1', 'TFRecord 1.0'
|
|
|
|
|
]:
|
|
|
|
|
# TO-DO: fix bug for this formats
|
|
|
|
|
continue
|
|
|
|
|
for user, edata in list(expected.items()):
|
|
|
|
|
project = copy.deepcopy(projects['main'])
|
|
|
|
|
if upload_format_name in tasks:
|
|
|
|
|
project['labels'] = tasks[upload_format_name]['labels']
|
|
|
|
|
project = self._create_project(project)
|
|
|
|
|
file_zip_name = osp.join(test_dir, f"{test_name}_{edata['name']}_{upload_format_name}.zip")
|
|
|
|
|
url = self._generate_url_upload_project_dataset(project['id'], upload_format_name)
|
|
|
|
|
|
|
|
|
|
if osp.exists(file_zip_name):
|
|
|
|
|
with open(file_zip_name, 'rb') as binary_file:
|
|
|
|
|
response = self._post_request_with_data(url, {"dataset_file": binary_file}, user)
|
|
|
|
|
self.assertEqual(response.status_code, edata['accept code'])
|
|
|
|
|
|
|
|
|
|
def test_api_v2_export_annotatios(self):
|
|
|
|
|
def test_api_v2_export_annotations(self):
|
|
|
|
|
test_name = self._testMethodName
|
|
|
|
|
dump_formats = dm.views.get_export_formats()
|
|
|
|
|
|
|
|
|
|
|