"""This file and its contents are licensed under the Apache License 2.0. Please see the included NOTICE for copyright information and LICENSE for a copy of the license. """ import glob import io import json import logging import os import pytest import yaml from core.label_config import parse_config, parse_config_to_json, validate_label_config from projects.models import Project from label_studio.tests.utils import make_annotation, make_prediction, make_task, project_id # noqa logger = logging.getLogger(__name__) @pytest.mark.parametrize( 'tasks_count, annotations_count, predictions_count', [ [2, 2, 2], ], ) @pytest.mark.django_db def test_change_label_config_repeater(tasks_count, annotations_count, predictions_count, business_client, project_id): # Change label config to Repeater payload = { 'label_config': '
' } response = business_client.patch( f'/api/projects/{project_id}', data=json.dumps(payload), content_type='application/json', ) assert response.status_code == 200 # cr project = Project.objects.get(pk=project_id) for _ in range(0, tasks_count): task_id = make_task( { 'data': { 'images': [ {'url': 'https://htx-pub.s3.amazonaws.com/demo/images/demo_stock_purchase_agreement/0001.jpg'}, {'url': 'https://htx-pub.s3.amazonaws.com/demo/images/demo_stock_purchase_agreement/0002.jpg'}, {'url': 'https://htx-pub.s3.amazonaws.com/demo/images/demo_stock_purchase_agreement/0003.jpg'}, ] } }, project, ).id print('TASK_ID: %s' % task_id) for _ in range(0, annotations_count): print('COMPLETION') make_annotation( { 'result': [ { 'id': '_565WKjviN', 'type': 'rectanglelabels', 'value': { 'x': 21.451104100946377, 'y': 7.682926829268292, 'width': 54.73186119873817, 'height': 4.146341463414634, 'rotation': 0, 'rectanglelabels': ['Header'], }, 'origin': 'manual', 'to_name': 'page_0', 'from_name': 'labels_0', 'image_rotation': 0, 'original_width': 800, 'original_height': 1035, } ] }, task_id, ) for _ in range(0, predictions_count): make_prediction({'result': []}, task_id) # no changes - no errors payload = { 'label_config': '
' } response = business_client.post( f'/api/projects/{project_id}/validate', data=json.dumps(payload), content_type='application/json', ) assert response.status_code == 200 # delete unused labels payload = { 'label_config': '
' } response = business_client.post( f'/api/projects/{project_id}/validate', data=json.dumps(payload), content_type='application/json', ) assert response.status_code == 200 # delete used labels - 400 payload = { 'label_config': '
' } response = business_client.post( f'/api/projects/{project_id}/validate', data=json.dumps(payload), content_type='application/json', ) assert response.status_code == 400 @pytest.mark.django_db def test_parse_all_configs(): folder_wildcard = './label_studio/annotation_templates' result = [y for x in os.walk(folder_wildcard) for y in glob.glob(os.path.join(x[0], '*.xml'))] for file in result: print(f'Parsing config: {file}') with open(file, mode='r') as f: config = f.read() assert parse_config(config) assert parse_config_to_json(config) validate_label_config(config) @pytest.mark.django_db def test_config_validation_for_choices_workaround(business_client, project_id): """ Validate Choices tag for 1 choice with workaround Example bug DEV-3635 """ payload = { 'label_config': '' '' '' '' } response = business_client.patch( f'/api/projects/{project_id}', data=json.dumps(payload), content_type='application/json', ) assert response.status_code == 200 payload = { 'label_config': '' '' '' } response = business_client.patch( f'/api/projects/{project_id}', data=json.dumps(payload), content_type='application/json', ) assert response.status_code == 200 @pytest.mark.django_db def test_config_validation_for_missing_to_name_in_number_tag_fails(business_client, project_id): """ Validate Number tag with missing to_name fails (see LEAP-245) """ payload = { 'label_config': ( '' '' '' '' ) } response = business_client.patch( f'/api/projects/{project_id}', data=json.dumps(payload), content_type='application/json', ) assert response.status_code == 400 response_data = response.json() assert "'toName' is a required property" in response_data['validation_errors']['label_config'][0] @pytest.mark.django_db def test_parse_wrong_xml(business_client, project_id): # Change label config to Repeater payload = { 'label_config': '
' } response = business_client.patch( f'/api/projects/{project_id}', data=json.dumps(payload), content_type='application/json', ) assert response.status_code == 200 # Change label config to wrong XML payload = { 'label_config': '1
' } response = business_client.post( f'/api/projects/{project_id}/validate', data=json.dumps(payload), content_type='application/json', ) assert response.status_code == 400 @pytest.mark.django_db def test_label_config_versions(business_client, project_id): with io.open(os.path.join(os.path.dirname(__file__), 'test_data/data_for_test_label_config_matrix.yml')) as f: test_suites = yaml.safe_load(f) for test_name, test_content in test_suites.items(): payload = {'label_config': test_content['label_config']} response = business_client.post( f'/api/projects/{project_id}/validate', data=json.dumps(payload), content_type='application/json', ) logger.warning(f'Test: {test_name}') assert response.status_code == test_content['status_code']