diff --git a/CHANGELOG.md b/CHANGELOG.md index 041f86f5b46..14ce75fb8f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -78,6 +78,7 @@ Tracks can be exported/imported to/from Datumaro and Sly Pointcloud formats () - Сreating a project or task with the same labels () - \[Server API\] Ability to rename label to an existing name () +- Moving a task to a project leads to reset of attributes () - Parsing skeleton sublabels containing spaces results in an error in dataset export () - Missing CVAT_BASE_URL in docker-compose.yml () diff --git a/cvat-ui/src/components/move-task-modal/label-mapper-item.tsx b/cvat-ui/src/components/move-task-modal/label-mapper-item.tsx index ad78c90f5e4..0cadf4445c2 100644 --- a/cvat-ui/src/components/move-task-modal/label-mapper-item.tsx +++ b/cvat-ui/src/components/move-task-modal/label-mapper-item.tsx @@ -6,14 +6,12 @@ import React from 'react'; import { Col, Row } from 'antd/lib/grid'; import Tag from 'antd/lib/tag'; import Select from 'antd/lib/select'; -import Checkbox from 'antd/lib/checkbox'; import { ArrowRightOutlined } from '@ant-design/icons'; import CVATTooltip from 'components/common/cvat-tooltip'; export interface LabelMapperItemValue { labelId: number; newLabelName: string | null; - clearAttributes: boolean; } export interface LabelMapperItemProps { @@ -62,18 +60,6 @@ export default function LabelMapperItem(props: LabelMapperItemProps): JSX.Elemen ))} - - onChange({ - ...value, - clearAttributes: _value.target.checked, - })} - > - Clear attributes - - ); } diff --git a/cvat-ui/src/components/move-task-modal/move-task-modal.tsx b/cvat-ui/src/components/move-task-modal/move-task-modal.tsx index 83007cff8ad..04dc7029cc2 100644 --- a/cvat-ui/src/components/move-task-modal/move-task-modal.tsx +++ b/cvat-ui/src/components/move-task-modal/move-task-modal.tsx @@ -49,7 +49,6 @@ function MoveTaskModal({ labelValues[labelId] = { labelId, newLabelName: null, - clearAttributes: true, }; }); } @@ -152,7 +151,6 @@ function MoveTaskModal({ labelValues[id] = { labelId: label.labelId, newLabelName: autoNewLabel ? autoNewLabel.name : null, - clearAttributes: true, }; }); setLabelMap(labelValues); diff --git a/cvat/apps/engine/serializers.py b/cvat/apps/engine/serializers.py index eacf7046687..da1c18f54f4 100644 --- a/cvat/apps/engine/serializers.py +++ b/cvat/apps/engine/serializers.py @@ -905,45 +905,51 @@ def update(self, instance, validated_data): project = models.Project.objects.get(id=validated_project_id) if project.tasks.count() and project.tasks.first().dimension != instance.dimension: raise serializers.ValidationError(f'Dimension ({instance.dimension}) of the task must be the same as other tasks in project ({project.tasks.first().dimension})') + if instance.project_id is None: - for old_label in instance.label_set.all(): - try: - if old_label.parent: - new_label = project.label_set.filter(name=old_label.name, parent__name=old_label.parent.name).first() - else: - new_label = project.label_set.filter(name=old_label.name).first() - except ValueError: - raise serializers.ValidationError(f'Target project does not have label with name "{old_label.name}"') - old_label.attributespec_set.all().delete() - for model in (models.LabeledTrack, models.LabeledShape, models.LabeledImage): - model.objects.filter(job__segment__task=instance, label=old_label).update( - label=new_label - ) - instance.label_set.all().delete() + label_set = instance.label_set.all() else: - for old_label in instance.project.label_set.all(): - new_label_for_name = list(filter(lambda x: x.get('id', None) == old_label.id, labels)) - if len(new_label_for_name): - old_label.name = new_label_for_name[0].get('name', old_label.name) - try: - if old_label.parent: - new_label = project.label_set.filter(name=old_label.name, parent__name=old_label.parent.name).first() - else: - new_label = project.label_set.filter(name=old_label.name).first() - except ValueError: - raise serializers.ValidationError(f'Target project does not have label with name "{old_label.name}"') - for (model, attr, attr_name) in ( - (models.LabeledTrack, models.LabeledTrackAttributeVal, 'track'), - (models.LabeledShape, models.LabeledShapeAttributeVal, 'shape'), - (models.LabeledImage, models.LabeledImageAttributeVal, 'image') + label_set = instance.project.label_set.all() + + for old_label in label_set: + new_label_for_name = list(filter(lambda x: x.get('id', None) == old_label.id, labels)) + if len(new_label_for_name): + old_label.name = new_label_for_name[0].get('name', old_label.name) + try: + if old_label.parent: + new_label = project.label_set.filter(name=old_label.name, parent__name=old_label.parent.name).first() + else: + new_label = project.label_set.filter(name=old_label.name).first() + except ValueError: + raise serializers.ValidationError(f'Target project does not have label with name "{old_label.name}"') + + for old_attr in old_label.attributespec_set.all(): + new_attr = new_label.attributespec_set.filter(name=old_attr.name, + values=old_attr.values, + input_type=old_attr.input_type).first() + if new_attr is None: + raise serializers.ValidationError('Target project does not have ' \ + f'"{old_label.name}" label with "{old_attr.name}" attribute') + + for (model, model_name) in ( + (models.LabeledTrackAttributeVal, 'track'), + (models.LabeledShapeAttributeVal, 'shape'), + (models.LabeledImageAttributeVal, 'image') ): - attr.objects.filter(**{ - f'{attr_name}__job__segment__task': instance, - f'{attr_name}__label': old_label - }).delete() - model.objects.filter(job__segment__task=instance, label=old_label).update( - label=new_label - ) + model.objects.filter(**{ + f'{model_name}__job__segment__task': instance, + f'{model_name}__label': old_label, + 'spec': old_attr + }).update(spec=new_attr) + + for model in (models.LabeledTrack, models.LabeledShape, models.LabeledImage): + model.objects.filter(job__segment__task=instance, label=old_label).update( + label=new_label + ) + + if instance.project_id is None: + instance.label_set.all().delete() + instance.project = project # update source and target storages diff --git a/cvat/apps/engine/tests/test_rest_api.py b/cvat/apps/engine/tests/test_rest_api.py index f9e7efb774a..00d6d0d48e9 100644 --- a/cvat/apps/engine/tests/test_rest_api.py +++ b/cvat/apps/engine/tests/test_rest_api.py @@ -2395,7 +2395,14 @@ def setUpTestData(cls): "name": "Project for task move 1", "owner": cls.admin, "labels": [{ - "name": "car" + "name": "car", + "attributes": [{ + "name": "color", + "mutable": False, + "input_type": AttributeType.SELECT, + "default_value": "white", + "values": ["white", "yellow", "green", "red"] + }] }, { "name": "person" }] diff --git a/tests/cypress/e2e/actions_projects_models/case_94_move_task_between_projects.js b/tests/cypress/e2e/actions_projects_models/case_94_move_task_between_projects.js index cbfc72d4d62..46eb20cb9c6 100644 --- a/tests/cypress/e2e/actions_projects_models/case_94_move_task_between_projects.js +++ b/tests/cypress/e2e/actions_projects_models/case_94_move_task_between_projects.js @@ -18,7 +18,7 @@ context('Move a task between projects.', () => { name: `Second project case ${caseID}`, label: 'bicycle', attrName: 'color', - attrVaue: 'yellow', + attrVaue: 'red', multiAttrParams: false, }; diff --git a/tests/cypress/e2e/actions_projects_models/case_95_move_task_to_project.js b/tests/cypress/e2e/actions_projects_models/case_95_move_task_to_project.js index c12ba47caf7..537d11eed89 100644 --- a/tests/cypress/e2e/actions_projects_models/case_95_move_task_to_project.js +++ b/tests/cypress/e2e/actions_projects_models/case_95_move_task_to_project.js @@ -15,9 +15,9 @@ context('Move a task to a project.', { browser: '!firefox' }, () => { attrName: 'Kind', attrValue: 'Oak', nameSecond: `Case ${caseID} second`, - labelSecond: 'Car', - attrNameSecons: 'Color', - attrValueSecond: 'Red', + labelSecond: 'Tree', + attrNameSecond: 'Kind', + attrValueSecond: 'Oak', name3d: `Case ${caseID} 3D`, label3d: 'Bus', attrName3d: 'Type', @@ -51,7 +51,7 @@ context('Move a task to a project.', { browser: '!firefox' }, () => { cy.createZipArchive(directoryToArchive, archivePath); cy.goToTaskList(); cy.createAnnotationTask( - task.nameSecond, task.labelSecond, task.attrNameSecons, task.attrValueSecond, archiveName, + task.nameSecond, task.labelSecond, task.attrNameSecond, task.attrValueSecond, archiveName, ); cy.createAnnotationTask(task.name3d, task.label3d, task.attrName3d, task.attrValue3d, archiveName3d); }); diff --git a/tests/python/rest_api/test_tasks.py b/tests/python/rest_api/test_tasks.py index f56e5a2168e..091fea1b8f3 100644 --- a/tests/python/rest_api/test_tasks.py +++ b/tests/python/rest_api/test_tasks.py @@ -976,7 +976,7 @@ def test_can_rename_label(self, tasks, labels, admin_user): assert DeepDiff(resulting_labels, task_labels, ignore_order=True) == {} def test_cannot_rename_label_to_duplicate_name(self, tasks, labels, admin_user): - task = [t for t in tasks if t["labels"]["count"] > 1][0] + task = [t for t in tasks if t["project_id"] is None and t["labels"]["count"] > 1][0] task_labels = deepcopy([l for l in labels if l.get("task_id") == task["id"]]) task_labels[0].update({"name": task_labels[1]["name"]}) @@ -1319,3 +1319,62 @@ def test_can_import_backup(self, fxt_task_with_unequal_jobs: Task): for old_job, new_job in zip(old_jobs, new_jobs): assert old_job.start_frame == new_job.start_frame assert old_job.stop_frame == new_job.stop_frame + + +@pytest.mark.usefixtures("restore_db_per_function") +class TestPatchTask: + @pytest.mark.parametrize("task_id, project_id, user", [(19, 12, "admin1")]) + def test_move_task_to_project_with_attributes(self, task_id, project_id, user): + response = get_method(user, f"tasks/{task_id}/annotations") + assert response.status_code == HTTPStatus.OK + annotations = response.json() + + response = patch_method(user, f"tasks/{task_id}", {"project_id": project_id}) + assert response.status_code == HTTPStatus.OK + + response = get_method(user, f"tasks/{task_id}") + assert response.status_code == HTTPStatus.OK + assert response.json().get("project_id") == project_id + + response = get_method(user, f"tasks/{task_id}/annotations") + assert response.status_code == HTTPStatus.OK + assert ( + DeepDiff( + annotations, + response.json(), + ignore_order=True, + exclude_regex_paths=[ + r"root\['\w+'\]\[\d+\]\['label_id'\]", + r"root\['\w+'\]\[\d+\]\['attributes'\]\[\d+\]\['spec_id'\]", + ], + ) + == {} + ) + + @pytest.mark.parametrize("task_id, project_id, user", [(20, 13, "admin1")]) + def test_move_task_from_one_project_to_another_with_attributes(self, task_id, project_id, user): + response = get_method(user, f"tasks/{task_id}/annotations") + assert response.status_code == HTTPStatus.OK + annotations = response.json() + + response = patch_method(user, f"tasks/{task_id}", {"project_id": project_id}) + assert response.status_code == HTTPStatus.OK + + response = get_method(user, f"tasks/{task_id}") + assert response.status_code == HTTPStatus.OK + assert response.json().get("project_id") == project_id + + response = get_method(user, f"tasks/{task_id}/annotations") + assert response.status_code == HTTPStatus.OK + assert ( + DeepDiff( + annotations, + response.json(), + ignore_order=True, + exclude_regex_paths=[ + r"root\['\w+'\]\[\d+\]\['label_id'\]", + r"root\['\w+'\]\[\d+\]\['attributes'\]\[\d+\]\['spec_id'\]", + ], + ) + == {} + ) diff --git a/tests/python/shared/assets/annotations.json b/tests/python/shared/assets/annotations.json index e962ea8ffca..e4f510b5e58 100644 --- a/tests/python/shared/assets/annotations.json +++ b/tests/python/shared/assets/annotations.json @@ -916,6 +916,120 @@ "tags": [], "tracks": [], "version": 0 + }, + "23": { + "shapes": [ + { + "attributes": [ + { + "spec_id": 7, + "value": "non-default" + } + ], + "elements": [], + "frame": 0, + "group": 0, + "id": 54, + "label_id": 51, + "occluded": false, + "outside": false, + "points": [ + 244.32906271072352, + 57.53054619015711, + 340.34389750505943, + 191.28914362778414 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + }, + { + "attributes": [ + { + "spec_id": 8, + "value": "black" + } + ], + "elements": [], + "frame": 0, + "group": 0, + "id": 55, + "label_id": 52, + "occluded": false, + "outside": false, + "points": [ + 424.4396493594086, + 86.6660822656795, + 664.8078219824692, + 251.54672960215976 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + } + ], + "tags": [], + "tracks": [], + "version": 0 + }, + "24": { + "shapes": [ + { + "attributes": [ + { + "spec_id": 9, + "value": "non-default" + } + ], + "elements": [], + "frame": 0, + "group": 0, + "id": 56, + "label_id": 53, + "occluded": false, + "outside": false, + "points": [ + 35.913636363637124, + 80.58636363636288, + 94.8227272727272, + 170.58636363636288 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + }, + { + "attributes": [ + { + "spec_id": 10, + "value": "black" + } + ], + "elements": [], + "frame": 0, + "group": 0, + "id": 57, + "label_id": 54, + "occluded": false, + "outside": false, + "points": [ + 190.95909090909117, + 100.22272727272684, + 297.7318181818191, + 209.8590909090908 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + } + ], + "tags": [], + "tracks": [], + "version": 0 } }, "task": { @@ -1816,6 +1930,120 @@ "tags": [], "tracks": [], "version": 0 + }, + "19": { + "shapes": [ + { + "attributes": [ + { + "spec_id": 7, + "value": "non-default" + } + ], + "elements": [], + "frame": 0, + "group": 0, + "id": 54, + "label_id": 51, + "occluded": false, + "outside": false, + "points": [ + 244.32906271072352, + 57.53054619015711, + 340.34389750505943, + 191.28914362778414 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + }, + { + "attributes": [ + { + "spec_id": 8, + "value": "black" + } + ], + "elements": [], + "frame": 0, + "group": 0, + "id": 55, + "label_id": 52, + "occluded": false, + "outside": false, + "points": [ + 424.4396493594086, + 86.6660822656795, + 664.8078219824692, + 251.54672960215976 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + } + ], + "tags": [], + "tracks": [], + "version": 0 + }, + "20": { + "shapes": [ + { + "attributes": [ + { + "spec_id": 9, + "value": "non-default" + } + ], + "elements": [], + "frame": 0, + "group": 0, + "id": 56, + "label_id": 53, + "occluded": false, + "outside": false, + "points": [ + 35.913636363637124, + 80.58636363636288, + 94.8227272727272, + 170.58636363636288 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + }, + { + "attributes": [ + { + "spec_id": 10, + "value": "black" + } + ], + "elements": [], + "frame": 0, + "group": 0, + "id": 57, + "label_id": 54, + "occluded": false, + "outside": false, + "points": [ + 190.95909090909117, + 100.22272727272684, + 297.7318181818191, + 209.8590909090908 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + } + ], + "tags": [], + "tracks": [], + "version": 0 } } } \ No newline at end of file diff --git a/tests/python/shared/assets/cvat_db/cvat_data.tar.bz2 b/tests/python/shared/assets/cvat_db/cvat_data.tar.bz2 index d3d6519fab8..0d0748fcb65 100644 Binary files a/tests/python/shared/assets/cvat_db/cvat_data.tar.bz2 and b/tests/python/shared/assets/cvat_db/cvat_data.tar.bz2 differ diff --git a/tests/python/shared/assets/cvat_db/data.json b/tests/python/shared/assets/cvat_db/data.json index e61e228ad66..787ef21a916 100644 --- a/tests/python/shared/assets/cvat_db/data.json +++ b/tests/python/shared/assets/cvat_db/data.json @@ -36,7 +36,7 @@ "pk": 1, "fields": { "password": "pbkdf2_sha256$260000$DevmxlmLwciP1P6sZs2Qag$U9DFtjTWx96Sk95qY6UXVcvpdQEP2LcoFBftk5D2RKY=", - "last_login": "2023-03-01T15:34:27.878Z", + "last_login": "2023-03-10T11:54:54.620Z", "is_superuser": true, "username": "admin1", "first_name": "Admin", @@ -615,6 +615,14 @@ "expire_date": "2021-12-28T19:44:48.529Z" } }, +{ + "model": "sessions.session", + "pk": "rmk4xete2em5m8rbllkk7d2nbd4q4rzg", + "fields": { + "session_data": ".eJxVjEEOwiAQRe_C2pDSDjC4dO8ZCMOAVA0kpV0Z765NutDtf-_9l_BhW4vfelr8zOIslDj9bhTiI9Ud8D3UW5Ox1XWZSe6KPGiX18bpeTncv4MSevnWzo0RtZ0MgAEmVg4HS2jdoAxqpAh5cmizNkwBIRlFEJzmEdhkVCTeH7LvNxA:1pabKo:-Qpngoe5m2XSdO9BYT01S3o_V8dldaxml3hDBR9GcNc", + "expire_date": "2023-03-24T11:54:54.631Z" + } +}, { "model": "sessions.session", "pk": "v28l0efbrv9x06z97ilwcf7lwtuf4ctc", @@ -1243,6 +1251,44 @@ "deleted_frames": "[]" } }, +{ + "model": "engine.data", + "pk": 18, + "fields": { + "chunk_size": 72, + "size": 2, + "image_quality": 70, + "start_frame": 0, + "stop_frame": 1, + "frame_filter": "", + "compressed_chunk_type": "imageset", + "original_chunk_type": "imageset", + "storage_method": "cache", + "storage": "local", + "cloud_storage": null, + "sorting_method": "lexicographical", + "deleted_frames": "[]" + } +}, +{ + "model": "engine.data", + "pk": 19, + "fields": { + "chunk_size": 72, + "size": 2, + "image_quality": 70, + "start_frame": 0, + "stop_frame": 1, + "frame_filter": "", + "compressed_chunk_type": "imageset", + "original_chunk_type": "imageset", + "storage_method": "cache", + "storage": "local", + "cloud_storage": null, + "sorting_method": "lexicographical", + "deleted_frames": "[]" + } +}, { "model": "engine.video", "pk": 1, @@ -2363,6 +2409,50 @@ "height": 483 } }, +{ + "model": "engine.image", + "pk": 453, + "fields": { + "data": 18, + "path": "15.png", + "frame": 0, + "width": 982, + "height": 376 + } +}, +{ + "model": "engine.image", + "pk": 454, + "fields": { + "data": 18, + "path": "16.png", + "frame": 1, + "width": 565, + "height": 365 + } +}, +{ + "model": "engine.image", + "pk": 455, + "fields": { + "data": 19, + "path": "33.png", + "frame": 0, + "width": 339, + "height": 351 + } +}, +{ + "model": "engine.image", + "pk": 456, + "fields": { + "data": 19, + "path": "34.png", + "frame": 1, + "width": 944, + "height": 271 + } +}, { "model": "engine.project", "pk": 1, @@ -2555,6 +2645,42 @@ "target_storage": 22 } }, +{ + "model": "engine.project", + "pk": 12, + "fields": { + "name": "project with attributes", + "owner": [ + "admin1" + ], + "assignee": null, + "bug_tracker": "", + "created_date": "2023-03-10T11:57:14.944Z", + "updated_date": "2023-03-10T11:57:48.747Z", + "status": "annotation", + "organization": null, + "source_storage": 27, + "target_storage": 28 + } +}, +{ + "model": "engine.project", + "pk": 13, + "fields": { + "name": "project with attributes 2", + "owner": [ + "admin1" + ], + "assignee": null, + "bug_tracker": "", + "created_date": "2023-03-10T11:58:04.216Z", + "updated_date": "2023-03-10T11:58:04.216Z", + "status": "annotation", + "organization": null, + "source_storage": 31, + "target_storage": 32 + } +}, { "model": "engine.task", "pk": 2, @@ -2896,6 +3022,56 @@ "target_storage": 24 } }, +{ + "model": "engine.task", + "pk": 19, + "fields": { + "project": null, + "name": "task with attributes", + "mode": "annotation", + "owner": [ + "admin1" + ], + "assignee": null, + "bug_tracker": "", + "created_date": "2023-03-10T11:56:33.757Z", + "updated_date": "2023-03-10T11:56:54.904Z", + "overlap": 0, + "segment_size": 2, + "status": "annotation", + "data": 18, + "dimension": "2d", + "subset": "", + "organization": null, + "source_storage": 25, + "target_storage": 26 + } +}, +{ + "model": "engine.task", + "pk": 20, + "fields": { + "project": 12, + "name": "task in project with attributes", + "mode": "annotation", + "owner": [ + "admin1" + ], + "assignee": null, + "bug_tracker": "", + "created_date": "2023-03-10T11:57:31.614Z", + "updated_date": "2023-03-10T11:57:48.835Z", + "overlap": 0, + "segment_size": 2, + "status": "annotation", + "data": 19, + "dimension": "2d", + "subset": "", + "organization": null, + "source_storage": 29, + "target_storage": 30 + } +}, { "model": "engine.clientfile", "pk": 131, @@ -3672,6 +3848,38 @@ "file": "/home/django/data/data/17/raw/13.png" } }, +{ + "model": "engine.clientfile", + "pk": 445, + "fields": { + "data": 18, + "file": "/home/django/data/data/18/raw/16.png" + } +}, +{ + "model": "engine.clientfile", + "pk": 446, + "fields": { + "data": 18, + "file": "/home/django/data/data/18/raw/15.png" + } +}, +{ + "model": "engine.clientfile", + "pk": 447, + "fields": { + "data": 19, + "file": "/home/django/data/data/19/raw/33.png" + } +}, +{ + "model": "engine.clientfile", + "pk": 448, + "fields": { + "data": 19, + "file": "/home/django/data/data/19/raw/34.png" + } +}, { "model": "engine.relatedfile", "pk": 1, @@ -3816,6 +4024,24 @@ "stop_frame": 1 } }, +{ + "model": "engine.segment", + "pk": 23, + "fields": { + "task": 19, + "start_frame": 0, + "stop_frame": 1 + } +}, +{ + "model": "engine.segment", + "pk": 24, + "fields": { + "task": 20, + "start_frame": 0, + "stop_frame": 1 + } +}, { "model": "engine.job", "pk": 2, @@ -4006,6 +4232,30 @@ "state": "in progress" } }, +{ + "model": "engine.job", + "pk": 23, + "fields": { + "segment": 23, + "assignee": null, + "updated_date": "2023-03-10T11:56:55.066Z", + "status": "annotation", + "stage": "annotation", + "state": "in progress" + } +}, +{ + "model": "engine.job", + "pk": 24, + "fields": { + "segment": 24, + "assignee": null, + "updated_date": "2023-03-10T11:57:49.019Z", + "status": "annotation", + "stage": "annotation", + "state": "in progress" + } +}, { "model": "engine.label", "pk": 3, @@ -4522,6 +4772,78 @@ "parent": 46 } }, +{ + "model": "engine.label", + "pk": 51, + "fields": { + "task": 19, + "project": null, + "name": "cat", + "color": "#6080c0", + "type": "any", + "parent": null + } +}, +{ + "model": "engine.label", + "pk": 52, + "fields": { + "task": 19, + "project": null, + "name": "car", + "color": "#2080c0", + "type": "any", + "parent": null + } +}, +{ + "model": "engine.label", + "pk": 53, + "fields": { + "task": null, + "project": 12, + "name": "cat", + "color": "#6080c0", + "type": "any", + "parent": null + } +}, +{ + "model": "engine.label", + "pk": 54, + "fields": { + "task": null, + "project": 12, + "name": "car", + "color": "#2080c0", + "type": "any", + "parent": null + } +}, +{ + "model": "engine.label", + "pk": 55, + "fields": { + "task": null, + "project": 13, + "name": "cat", + "color": "#6080c0", + "type": "any", + "parent": null + } +}, +{ + "model": "engine.label", + "pk": 56, + "fields": { + "task": null, + "project": 13, + "name": "car", + "color": "#2080c0", + "type": "any", + "parent": null + } +}, { "model": "engine.skeleton", "pk": 1, @@ -4614,6 +4936,78 @@ "values": "false" } }, +{ + "model": "engine.attributespec", + "pk": 7, + "fields": { + "label": 51, + "name": "attr", + "mutable": false, + "input_type": "text", + "default_value": "default", + "values": "default" + } +}, +{ + "model": "engine.attributespec", + "pk": 8, + "fields": { + "label": 52, + "name": "color", + "mutable": false, + "input_type": "radio", + "default_value": "white", + "values": "white\nblack\nred" + } +}, +{ + "model": "engine.attributespec", + "pk": 9, + "fields": { + "label": 53, + "name": "attr", + "mutable": false, + "input_type": "text", + "default_value": "default", + "values": "default" + } +}, +{ + "model": "engine.attributespec", + "pk": 10, + "fields": { + "label": 54, + "name": "color", + "mutable": false, + "input_type": "radio", + "default_value": "white", + "values": "white\nblack\nred" + } +}, +{ + "model": "engine.attributespec", + "pk": 11, + "fields": { + "label": 55, + "name": "attr", + "mutable": false, + "input_type": "text", + "default_value": "default", + "values": "default" + } +}, +{ + "model": "engine.attributespec", + "pk": 12, + "fields": { + "label": 56, + "name": "color", + "mutable": false, + "input_type": "radio", + "default_value": "white", + "values": "white\nblack\nred" + } +}, { "model": "engine.labeledimage", "pk": 1, @@ -5162,6 +5556,78 @@ "parent": 49 } }, +{ + "model": "engine.labeledshape", + "pk": 54, + "fields": { + "job": 23, + "label": 51, + "frame": 0, + "group": 0, + "source": "manual", + "type": "rectangle", + "occluded": false, + "outside": false, + "z_order": 0, + "points": "[244.32906271072352, 57.53054619015711, 340.34389750505943, 191.28914362778414]", + "rotation": 0.0, + "parent": null + } +}, +{ + "model": "engine.labeledshape", + "pk": 55, + "fields": { + "job": 23, + "label": 52, + "frame": 0, + "group": 0, + "source": "manual", + "type": "rectangle", + "occluded": false, + "outside": false, + "z_order": 0, + "points": "[424.4396493594086, 86.6660822656795, 664.8078219824692, 251.54672960215976]", + "rotation": 0.0, + "parent": null + } +}, +{ + "model": "engine.labeledshape", + "pk": 56, + "fields": { + "job": 24, + "label": 53, + "frame": 0, + "group": 0, + "source": "manual", + "type": "rectangle", + "occluded": false, + "outside": false, + "z_order": 0, + "points": "[35.913636363637124, 80.58636363636288, 94.8227272727272, 170.58636363636288]", + "rotation": 0.0, + "parent": null + } +}, +{ + "model": "engine.labeledshape", + "pk": 57, + "fields": { + "job": 24, + "label": 54, + "frame": 0, + "group": 0, + "source": "manual", + "type": "rectangle", + "occluded": false, + "outside": false, + "z_order": 0, + "points": "[190.95909090909117, 100.22272727272684, 297.7318181818191, 209.8590909090908]", + "rotation": 0.0, + "parent": null + } +}, { "model": "engine.labeledshapeattributeval", "pk": 1, @@ -5189,6 +5655,42 @@ "shape": 42 } }, +{ + "model": "engine.labeledshapeattributeval", + "pk": 4, + "fields": { + "spec": 7, + "value": "non-default", + "shape": 54 + } +}, +{ + "model": "engine.labeledshapeattributeval", + "pk": 5, + "fields": { + "spec": 8, + "value": "black", + "shape": 55 + } +}, +{ + "model": "engine.labeledshapeattributeval", + "pk": 6, + "fields": { + "spec": 9, + "value": "non-default", + "shape": 56 + } +}, +{ + "model": "engine.labeledshapeattributeval", + "pk": 7, + "fields": { + "spec": 10, + "value": "black", + "shape": 57 + } +}, { "model": "engine.labeledtrack", "pk": 1, @@ -6026,6 +6528,70 @@ "cloud_storage_id": null } }, +{ + "model": "engine.storage", + "pk": 25, + "fields": { + "location": "local", + "cloud_storage_id": null + } +}, +{ + "model": "engine.storage", + "pk": 26, + "fields": { + "location": "local", + "cloud_storage_id": null + } +}, +{ + "model": "engine.storage", + "pk": 27, + "fields": { + "location": "local", + "cloud_storage_id": null + } +}, +{ + "model": "engine.storage", + "pk": 28, + "fields": { + "location": "local", + "cloud_storage_id": null + } +}, +{ + "model": "engine.storage", + "pk": 29, + "fields": { + "location": "local", + "cloud_storage_id": null + } +}, +{ + "model": "engine.storage", + "pk": 30, + "fields": { + "location": "local", + "cloud_storage_id": null + } +}, +{ + "model": "engine.storage", + "pk": 31, + "fields": { + "location": "local", + "cloud_storage_id": null + } +}, +{ + "model": "engine.storage", + "pk": 32, + "fields": { + "location": "local", + "cloud_storage_id": null + } +}, { "model": "webhooks.webhook", "pk": 1, diff --git a/tests/python/shared/assets/jobs.json b/tests/python/shared/assets/jobs.json index 9866c2e2589..397e4666f53 100644 --- a/tests/python/shared/assets/jobs.json +++ b/tests/python/shared/assets/jobs.json @@ -1,8 +1,60 @@ { - "count": 15, + "count": 17, "next": null, "previous": null, "results": [ + { + "assignee": null, + "bug_tracker": "", + "data_chunk_size": 72, + "data_compressed_chunk_type": "imageset", + "dimension": "2d", + "id": 24, + "issues": { + "count": 0, + "url": "http://localhost:8080/api/issues?job_id=24" + }, + "labels": { + "count": 2, + "url": "http://localhost:8080/api/labels?job_id=24" + }, + "mode": "annotation", + "project_id": 12, + "stage": "annotation", + "start_frame": 0, + "state": "in progress", + "status": "annotation", + "stop_frame": 1, + "task_id": 20, + "updated_date": "2023-03-10T11:57:49.019000Z", + "url": "http://localhost:8080/api/jobs/24" + }, + { + "assignee": null, + "bug_tracker": null, + "data_chunk_size": 72, + "data_compressed_chunk_type": "imageset", + "dimension": "2d", + "id": 23, + "issues": { + "count": 0, + "url": "http://localhost:8080/api/issues?job_id=23" + }, + "labels": { + "count": 2, + "url": "http://localhost:8080/api/labels?job_id=23" + }, + "mode": "annotation", + "project_id": null, + "stage": "annotation", + "start_frame": 0, + "state": "in progress", + "status": "annotation", + "stop_frame": 1, + "task_id": 19, + "updated_date": "2023-03-10T11:56:55.066000Z", + "url": "http://localhost:8080/api/jobs/23" + }, { "assignee": null, "bug_tracker": "", diff --git a/tests/python/shared/assets/labels.json b/tests/python/shared/assets/labels.json index 430e791d56f..888efff4768 100644 --- a/tests/python/shared/assets/labels.json +++ b/tests/python/shared/assets/labels.json @@ -1,5 +1,5 @@ { - "count": 27, + "count": 33, "next": null, "previous": null, "results": [ @@ -494,6 +494,144 @@ ], "svg": "", "type": "skeleton" + }, + { + "attributes": [ + { + "default_value": "default", + "id": 7, + "input_type": "text", + "mutable": false, + "name": "attr", + "values": [ + "default" + ] + } + ], + "color": "#6080c0", + "has_parent": false, + "id": 51, + "name": "cat", + "parent_id": null, + "sublabels": [], + "task_id": 19, + "type": "any" + }, + { + "attributes": [ + { + "default_value": "white", + "id": 8, + "input_type": "radio", + "mutable": false, + "name": "color", + "values": [ + "white", + "black", + "red" + ] + } + ], + "color": "#2080c0", + "has_parent": false, + "id": 52, + "name": "car", + "parent_id": null, + "sublabels": [], + "task_id": 19, + "type": "any" + }, + { + "attributes": [ + { + "default_value": "default", + "id": 9, + "input_type": "text", + "mutable": false, + "name": "attr", + "values": [ + "default" + ] + } + ], + "color": "#6080c0", + "has_parent": false, + "id": 53, + "name": "cat", + "parent_id": null, + "project_id": 12, + "sublabels": [], + "type": "any" + }, + { + "attributes": [ + { + "default_value": "white", + "id": 10, + "input_type": "radio", + "mutable": false, + "name": "color", + "values": [ + "white", + "black", + "red" + ] + } + ], + "color": "#2080c0", + "has_parent": false, + "id": 54, + "name": "car", + "parent_id": null, + "project_id": 12, + "sublabels": [], + "type": "any" + }, + { + "attributes": [ + { + "default_value": "default", + "id": 11, + "input_type": "text", + "mutable": false, + "name": "attr", + "values": [ + "default" + ] + } + ], + "color": "#6080c0", + "has_parent": false, + "id": 55, + "name": "cat", + "parent_id": null, + "project_id": 13, + "sublabels": [], + "type": "any" + }, + { + "attributes": [ + { + "default_value": "white", + "id": 12, + "input_type": "radio", + "mutable": false, + "name": "color", + "values": [ + "white", + "black", + "red" + ] + } + ], + "color": "#2080c0", + "has_parent": false, + "id": 56, + "name": "car", + "parent_id": null, + "project_id": 13, + "sublabels": [], + "type": "any" } ] } \ No newline at end of file diff --git a/tests/python/shared/assets/projects.json b/tests/python/shared/assets/projects.json index 6b77a35cfd1..aec99dea29e 100644 --- a/tests/python/shared/assets/projects.json +++ b/tests/python/shared/assets/projects.json @@ -1,8 +1,84 @@ { - "count": 10, + "count": 12, "next": null, "previous": null, "results": [ + { + "assignee": null, + "bug_tracker": "", + "created_date": "2023-03-10T11:58:04.216000Z", + "dimension": null, + "id": 13, + "labels": { + "count": 2, + "url": "http://localhost:8080/api/labels?project_id=13" + }, + "name": "project with attributes 2", + "organization": null, + "owner": { + "first_name": "Admin", + "id": 1, + "last_name": "First", + "url": "http://localhost:8080/api/users/1", + "username": "admin1" + }, + "source_storage": { + "cloud_storage_id": null, + "id": 31, + "location": "local" + }, + "status": "annotation", + "target_storage": { + "cloud_storage_id": null, + "id": 32, + "location": "local" + }, + "task_subsets": [], + "tasks": { + "count": 0, + "url": "http://localhost:8080/api/tasks?project_id=13" + }, + "updated_date": "2023-03-10T11:58:04.216000Z", + "url": "http://localhost:8080/api/projects/13" + }, + { + "assignee": null, + "bug_tracker": "", + "created_date": "2023-03-10T11:57:14.944000Z", + "dimension": "2d", + "id": 12, + "labels": { + "count": 2, + "url": "http://localhost:8080/api/labels?project_id=12" + }, + "name": "project with attributes", + "organization": null, + "owner": { + "first_name": "Admin", + "id": 1, + "last_name": "First", + "url": "http://localhost:8080/api/users/1", + "username": "admin1" + }, + "source_storage": { + "cloud_storage_id": null, + "id": 27, + "location": "local" + }, + "status": "annotation", + "target_storage": { + "cloud_storage_id": null, + "id": 28, + "location": "local" + }, + "task_subsets": [], + "tasks": { + "count": 1, + "url": "http://localhost:8080/api/tasks?project_id=12" + }, + "updated_date": "2023-03-10T11:57:48.747000Z", + "url": "http://localhost:8080/api/projects/12" + }, { "assignee": null, "bug_tracker": "", diff --git a/tests/python/shared/assets/tasks.json b/tests/python/shared/assets/tasks.json index 46bc6d54bcb..ff1fdb19e00 100644 --- a/tests/python/shared/assets/tasks.json +++ b/tests/python/shared/assets/tasks.json @@ -1,8 +1,106 @@ { - "count": 13, + "count": 15, "next": null, "previous": null, "results": [ + { + "assignee": null, + "bug_tracker": "", + "created_date": "2023-03-10T11:57:31.614000Z", + "data": 19, + "data_chunk_size": 72, + "data_compressed_chunk_type": "imageset", + "data_original_chunk_type": "imageset", + "dimension": "2d", + "id": 20, + "image_quality": 70, + "jobs": { + "completed": 0, + "count": 1, + "url": "http://localhost:8080/api/jobs?task_id=20" + }, + "labels": { + "count": 2, + "url": "http://localhost:8080/api/labels?task_id=20" + }, + "mode": "annotation", + "name": "task in project with attributes", + "organization": null, + "overlap": 0, + "owner": { + "first_name": "Admin", + "id": 1, + "last_name": "First", + "url": "http://localhost:8080/api/users/1", + "username": "admin1" + }, + "project_id": 12, + "segment_size": 2, + "size": 2, + "source_storage": { + "cloud_storage_id": null, + "id": 29, + "location": "local" + }, + "status": "annotation", + "subset": "", + "target_storage": { + "cloud_storage_id": null, + "id": 30, + "location": "local" + }, + "updated_date": "2023-03-10T11:57:48.835000Z", + "url": "http://localhost:8080/api/tasks/20" + }, + { + "assignee": null, + "bug_tracker": "", + "created_date": "2023-03-10T11:56:33.757000Z", + "data": 18, + "data_chunk_size": 72, + "data_compressed_chunk_type": "imageset", + "data_original_chunk_type": "imageset", + "dimension": "2d", + "id": 19, + "image_quality": 70, + "jobs": { + "completed": 0, + "count": 1, + "url": "http://localhost:8080/api/jobs?task_id=19" + }, + "labels": { + "count": 2, + "url": "http://localhost:8080/api/labels?task_id=19" + }, + "mode": "annotation", + "name": "task with attributes", + "organization": null, + "overlap": 0, + "owner": { + "first_name": "Admin", + "id": 1, + "last_name": "First", + "url": "http://localhost:8080/api/users/1", + "username": "admin1" + }, + "project_id": null, + "segment_size": 2, + "size": 2, + "source_storage": { + "cloud_storage_id": null, + "id": 25, + "location": "local" + }, + "status": "annotation", + "subset": "", + "target_storage": { + "cloud_storage_id": null, + "id": 26, + "location": "local" + }, + "updated_date": "2023-03-10T11:56:54.904000Z", + "url": "http://localhost:8080/api/tasks/19" + }, { "assignee": null, "bug_tracker": "", diff --git a/tests/python/shared/assets/users.json b/tests/python/shared/assets/users.json index efc89658789..6eca94d2e10 100644 --- a/tests/python/shared/assets/users.json +++ b/tests/python/shared/assets/users.json @@ -310,7 +310,7 @@ "is_active": true, "is_staff": true, "is_superuser": true, - "last_login": "2023-03-01T15:34:27.878000Z", + "last_login": "2023-03-10T11:54:54.620000Z", "last_name": "First", "url": "http://localhost:8080/api/users/1", "username": "admin1"