def test_image_quality_setting2(tmpdir): tmpdir = Path(tmpdir) projects = sa.search_projects(PROJECT_NAME2, return_metadata=True) for project in projects: sa.delete_project(project) project = sa.create_project(PROJECT_NAME2, "test", "Vector") sa.set_project_default_image_quality_in_editor(project, "original") sa.upload_images_from_folder_to_project(project, "./tests/sample_project_vector") sa.download_image(project, "example_image_1.jpg", tmpdir, variant="lores") assert filecmp.cmp(tmpdir / "example_image_1.jpg___lores.jpg", "./tests/sample_project_vector/example_image_1.jpg", shallow=False)
def test_supervisely_convert_keypoint(tmpdir): input_dir = Path( 'tests' ) / 'converter_test' / 'Supervisely' / 'input' / 'toSuperAnnotate' / 'keypoints' out_dir = Path(tmpdir) / 'keypoint_detection' sa.import_annotation_format(input_dir, out_dir, 'Supervisely', '', 'Vector', 'keypoint_detection', 'Web') project_name = "supervisely_test_keypoint" projects = sa.search_projects(project_name, True) if projects: sa.delete_project(projects[0]) project = sa.create_project(project_name, "converter vector", "Vector") sa.create_annotation_classes_from_classes_json( project, out_dir / "classes" / "classes.json") sa.upload_images_from_folder_to_project(project, out_dir) sa.upload_annotations_from_folder_to_project(project, out_dir)
def test_supervisely_convert_instance_pixel(tmpdir): input_dir = Path( 'tests' ) / 'converter_test' / 'Supervisely' / 'input' / 'toSuperAnnotate' / 'instance' out_dir = Path(tmpdir) / 'instance_segmentation_pixel' sa.import_annotation_format(input_dir, out_dir, 'Supervisely', '', 'Pixel', 'instance_segmentation', 'Web') project_name = "supervisely_test_instance_pixel" projects = sa.search_projects(project_name, True) if projects: sa.delete_project(projects[0]) project = sa.create_project(project_name, "converter vector", "Pixel") sa.create_annotation_classes_from_classes_json( project, out_dir / "classes" / "classes.json") sa.upload_images_from_folder_to_project(project, out_dir) sa.upload_annotations_from_folder_to_project(project, out_dir)
def test_coco_pixel_instance(tmpdir): input_dir = Path( "tests" ) / "converter_test" / "COCO" / "input" / "toSuperAnnotate" / "instance_segmentation" out_dir = Path(tmpdir) / "instance_pixel" sa.import_annotation_format(input_dir, out_dir, "COCO", "instances_test", "Pixel", "instance_segmentation", "Web") project_name = "coco2sa_pixel_instance" projects = sa.search_projects(project_name, True) if projects: sa.delete_project(projects[0]) project = sa.create_project(project_name, "converter vector", "Pixel") sa.create_annotation_classes_from_classes_json( project, out_dir / "classes" / "classes.json") sa.upload_images_from_folder_to_project(project, out_dir) sa.upload_annotations_from_folder_to_project(project, out_dir)
def vott_convert_vector(tmpdir): out_dir = tmpdir / "vector_annotation" sa.import_annotation_format( "tests/converter_test/VoTT/input/toSuperAnnotate", str(out_dir), "VoTT", "", "Vector", "vector_annotation", "Web") project_name = "vott_vector" projects = sa.search_projects(project_name, True) if projects: sa.delete_project(projects[0]) project = sa.create_project(project_name, "converter vector", "Vector") sa.create_annotation_classes_from_classes_json( project, out_dir / "classes" / "classes.json") sa.upload_images_from_folder_to_project(project, out_dir) sa.upload_annotations_from_folder_to_project(project, out_dir) return 0
def supervisely_convert_keypoint(tmpdir): out_dir = tmpdir / 'keypoint_detection' sa.import_annotation_format( 'tests/converter_test/Supervisely/input/toSuperAnnotate/keypoints', str(out_dir), 'Supervisely', '', 'Vector', 'keypoint_detection', 'Web') project_name = "supervisely_test_keypoint" projects = sa.search_projects(project_name, True) if projects: sa.delete_project(projects[0]) project = sa.create_project(project_name, "converter vector", "Vector") sa.create_annotation_classes_from_classes_json( project, out_dir / "classes" / "classes.json") sa.upload_images_from_folder_to_project(project, out_dir) sa.upload_annotations_from_folder_to_project(project, out_dir) return 0
def test_single_image_upload_s3(tmpdir): tmpdir = Path(tmpdir) projects_found = sa.search_projects(PROJECT_NAME_S3, return_metadata=True) for pr in projects_found: sa.delete_project(pr) project = sa.create_project(PROJECT_NAME_S3, "test", "Vector") sa.upload_image_to_project(project, "sample_project_vector/example_image_1.jpg", annotation_status="InProgress", from_s3_bucket="superannotate-python-sdk-test") images = sa.search_images(project) assert len(images) == 1 image = images[0] assert sa.get_image_metadata(project, image)["annotation_status"] == "InProgress"
def test_voc_vector_instance(tmpdir): input_dir = Path( "tests" ) / "converter_test" / "VOC" / "input" / "fromPascalVOCToSuperAnnotate" / "VOC2012" out_dir = Path(tmpdir) / "instance_vector" sa.import_annotation_format(input_dir, out_dir, "VOC", "", "Vector", "instance_segmentation", "Web") project_name = "voc2sa_vector_instance" projects = sa.search_projects(project_name, True) if projects: sa.delete_project(projects[0]) project = sa.create_project(project_name, "converter vector", "Vector") sa.create_annotation_classes_from_classes_json( project, out_dir / "classes" / "classes.json") sa.upload_images_from_folder_to_project(project, out_dir) sa.upload_annotations_from_folder_to_project(project, out_dir)
def test_export_s3(tmpdir): paginator = s3_client.get_paginator('list_objects_v2') response_iterator = paginator.paginate(Bucket=S3_BUCKET, Prefix=S3_PREFIX2) for response in response_iterator: if 'Contents' in response: for object_data in response['Contents']: key = object_data['Key'] s3_client.delete_object(Bucket=S3_BUCKET, Key=key) tmpdir = Path(tmpdir) projects = sa.search_projects(PROJECT_NAME_EXPORT, return_metadata=True) for project in projects: sa.delete_project(project) project = sa.create_project(PROJECT_NAME_EXPORT, "test", "Vector") sa.upload_images_from_folder_to_project( project, Path("./tests/sample_project_vector"), annotation_status="InProgress") sa.create_annotation_classes_from_classes_json( project, Path("./tests/sample_project_vector/classes/classes.json")) sa.upload_annotations_from_folder_to_project( project, Path("./tests/sample_project_vector")) images = sa.search_images(project) for img in images: sa.set_image_annotation_status(project, img, 'QualityCheck') new_export = sa.prepare_export(project, include_fuse=True) sa.download_export(project, new_export, S3_PREFIX2, to_s3_bucket=S3_BUCKET) files = [] response_iterator = paginator.paginate(Bucket=S3_BUCKET, Prefix=S3_PREFIX2) for response in response_iterator: if 'Contents' in response: for object_data in response['Contents']: key = object_data['Key'] files.append(key) output_path = tmpdir / S3_PREFIX2 output_path.mkdir() sa.download_export(project, new_export, output_path) local_files = list(output_path.rglob("*.*")) assert len(local_files) == len(files)
def supervisely_convert_instance_pixel(tmpdir): out_dir = tmpdir / 'instance_segmentation_pixel' sa.import_annotation_format( 'tests/converter_test/Supervisely/input/toSuperAnnotate/instance', str(out_dir), 'Supervisely', '', 'Pixel', 'instance_segmentation', 'Web') project_name = "supervisely_test_instance_pixel" projects = sa.search_projects(project_name, True) if projects: sa.delete_project(projects[0]) project = sa.create_project(project_name, "converter vector", "Pixel") sa.create_annotation_classes_from_classes_json( project, out_dir / "classes" / "classes.json") sa.upload_images_from_folder_to_project(project, out_dir) sa.upload_annotations_from_folder_to_project(project, out_dir) return 0
def test_attach_image_urls(): projects = sa.search_projects(PROJECT_NAME_VECTOR, return_metadata=True) for project in projects: sa.delete_project(project) project = sa.create_project(PROJECT_NAME_VECTOR, "test", "Vector") uploaded, could_not_upload, existing_images = sa.attach_image_urls_to_project( project, PATH_TO_URLS) assert len(uploaded) == 7 assert len(could_not_upload) == 0 assert len(existing_images) == 1 uploaded, could_not_upload, existing_images = sa.attach_image_urls_to_project( project, PATH_TO_URLS) assert len(uploaded) == 2 assert len(could_not_upload) == 0 assert len(existing_images) == 6
def sagemaker_object_detection(tmpdir): out_dir = tmpdir / "object_detection" sa.import_annotation_format( 'tests/converter_test/SageMaker/input/toSuperAnnotate/object_detection', str(out_dir), 'SageMaker', 'test-obj-detect', 'Vector', 'object_detection', 'Web') project_name = "sagemaker_object_detection" projects = sa.search_projects(project_name, True) if projects: sa.delete_project(projects[0]) project = sa.create_project(project_name, "converter vector", "Vector") sa.create_annotation_classes_from_classes_json( project, out_dir + "/classes/classes.json") sa.upload_images_from_folder_to_project(project, out_dir) sa.upload_annotations_from_folder_to_project(project, out_dir) return 0
def test_coco_vector_keypoint(tmpdir): input_dir = Path( "tests" ) / "converter_test" / "COCO" / "input" / "toSuperAnnotate" / "keypoint_detection/" out_dir = Path(tmpdir) / "vector_keypoint" sa.import_annotation_format(input_dir, out_dir, "COCO", "person_keypoints_test", "Vector", "keypoint_detection", "Web") project_name = "coco2sa_keypoint" projects = sa.search_projects(project_name, True) if projects: sa.delete_project(projects[0]) project = sa.create_project(project_name, "converter vector", "Vector") sa.create_annotation_classes_from_classes_json( project, out_dir / "classes" / "classes.json") sa.upload_images_from_folder_to_project(project, out_dir) sa.upload_annotations_from_folder_to_project(project, out_dir)
def test_dataloop_convert_vector(tmpdir): input_dir = Path( 'tests' ) / 'converter_test' / 'DataLoop' / 'input' / 'toSuperAnnotate' out_dir = Path(tmpdir) / 'output_vector' sa.import_annotation_format( input_dir, out_dir, 'DataLoop', '', 'Vector', 'vector_annotation', 'Web' ) project_name = "dataloop_test_vector" projects = sa.search_projects(project_name, True) if projects: sa.delete_project(projects[0]) project = sa.create_project(project_name, "converter vector", "Vector") sa.create_annotation_classes_from_classes_json( project, out_dir / "classes" / "classes.json" ) sa.upload_images_from_folder_to_project(project, out_dir) sa.upload_annotations_from_folder_to_project(project, out_dir)
def coco_pixel_instance(tmpdir): out_dir = tmpdir / "instance_pixel" sa.import_annotation_format( "tests/converter_test/COCO/input/toSuperAnnotate/instance_segmentation/", str(out_dir), "COCO", "instances_test", "Pixel", "instance_segmentation", "Web") project_name = "coco2sa_pixel_instance" projects = sa.search_projects(project_name, True) if projects: sa.delete_project(projects[0]) project = sa.create_project(project_name, "converter vector", "Pixel") sa.create_annotation_classes_from_classes_json( project, out_dir / "classes" / "classes.json") sa.upload_images_from_folder_to_project(project, out_dir) sa.upload_annotations_from_folder_to_project(project, out_dir) return 0
def test_upload_stress(tmpdir): tmpdir = Path(tmpdir) projects = sa.search_projects(PROJECT_NAME, return_metadata=True) for project in projects: sa.delete_project(project) project = sa.create_project(PROJECT_NAME, "hk", "Vector") sa.create_annotation_classes_from_classes_json( project, "tests/sample_project_vector/classes/classes.json" ) sa.upload_images_from_folder_to_project( project, "/media/disc_drive/datasets/COCO/test2017", annotation_status="QualityCheck" ) time.sleep(60) count = sa.get_project_image_count(project) assert count == 40670
def coco_vector_keypoint(tmpdir): out_dir = tmpdir / "vector_keypoint" sa.import_annotation_format( "tests/converter_test/COCO/input/toSuperAnnotate/keypoint_detection/", str(out_dir), "COCO", "person_keypoints_test", "Vector", "keypoint_detection", "Web") project_name = "coco2sa_keypoint" projects = sa.search_projects(project_name, True) if projects: sa.delete_project(projects[0]) project = sa.create_project(project_name, "converter vector", "Vector") sa.create_annotation_classes_from_classes_json( project, out_dir / "classes" / "classes.json") sa.upload_images_from_folder_to_project(project, out_dir) sa.upload_annotations_from_folder_to_project(project, out_dir) return 0
def googlecloud_convert_web(tmpdir): out_dir = tmpdir / "output_web" sa.import_annotation_format( "tests/converter_test/GoogleCloud/input/toSuperAnnotate", str(out_dir), "GoogleCloud", "image_object_detection", "Vector", "object_detection", "Web") project_name = "googlcloud_vector" projects = sa.search_projects(project_name, True) if projects: sa.delete_project(projects[0]) project = sa.create_project(project_name, "converter vector", "Vector") sa.create_annotation_classes_from_classes_json( project, out_dir / "classes" / "classes.json") sa.upload_images_from_folder_to_project(project, out_dir) sa.upload_annotations_from_folder_to_project(project, out_dir) return 0
def yolo_object_detection_web(tmpdir): out_dir = tmpdir / "vector_annotation_web" sa.import_annotation_format( 'tests/converter_test/YOLO/input/toSuperAnnotate', str(out_dir), 'YOLO', '', 'Vector', 'object_detection', 'Web' ) project_name = "yolo_object_detection" projects = sa.search_projects(project_name, True) if projects: sa.delete_project(projects[0]) project = sa.create_project(project_name, "converter vector", "Vector") sa.create_annotation_classes_from_classes_json( project, out_dir + "/classes/classes.json" ) sa.upload_images_from_folder_to_project(project, out_dir) sa.upload_annotations_from_folder_to_project(project, out_dir) return 0
def test_vott_convert_object(tmpdir): input_dir = Path( "tests" ) / "converter_test" / "VoTT" / "input" / "toSuperAnnotate" out_dir = Path(tmpdir) / "object_detection" sa.import_annotation_format( input_dir, out_dir, "VoTT", "", "Vector", "object_detection", "Web" ) project_name = "vott_object" projects = sa.search_projects(project_name, True) if projects: sa.delete_project(projects[0]) project = sa.create_project(project_name, "converter vector", "Vector") sa.create_annotation_classes_from_classes_json( project, out_dir / "classes" / "classes.json" ) sa.upload_images_from_folder_to_project(project, out_dir) sa.upload_annotations_from_folder_to_project(project, out_dir)
def test_single_image_upload(tmpdir): tmpdir = Path(tmpdir) projects_found = sa.search_projects(PROJECT_NAME, return_metadata=True) print(projects_found) for pr in projects_found: sa.delete_project(pr) project = sa.create_project(PROJECT_NAME, "test", "Vector") sa.upload_image_to_project( project, "./tests/sample_project_vector/example_image_1.jpg", annotation_status="InProgress") images = sa.search_images(project) assert len(images) == 1 image = images[0] assert sa.get_image_metadata(project, image)["annotation_status"] == "InProgress" assert image == "example_image_1.jpg"
def test_upload_images_from_azure_storage_to_project(): folder_path_with_test_imgs = 'cat_pics_sdk_test' folder_path_nested = 'cat_pics_nested_test' folder_path_non_existent = 'nonex' test_folders = [(folder_path_with_test_imgs, [6, 0, 6, 0]), (folder_path_nested, [0, 6, 0, 0]), (folder_path_non_existent, [0, 0, 0, 0])] if sa.search_projects(PROJECT_NAME) != []: sa.delete_project(PROJECT_NAME) proj_data = sa.create_project(PROJECT_NAME, "test", "Vector") for folder_path, true_res in test_folders: uploaded_urls, uploaded_filenames, duplicate_filenames, not_uploaded_urls = sa.upload_images_from_azure_blob_to_project( proj_data, CONTAINER_NAME, folder_path, annotation_status='InProgress', image_quality_in_editor="original") assert len(uploaded_urls) == true_res[0] assert len(duplicate_filenames) == true_res[1] assert len(uploaded_filenames) == true_res[2] assert len(not_uploaded_urls) == true_res[3]
def voc_vector_instance(tmpdir): out_dir = tmpdir / "instance_vector" sa.import_annotation_format( "tests/converter_test/VOC/input/fromPascalVOCToSuperAnnotate/VOC2012/", str(out_dir), "VOC", "", "Vector", "instance_segmentation", "Web" ) project_name = "voc2sa_vector_instance" projects = sa.search_projects(project_name, True) if projects: sa.delete_project(projects[0]) project = sa.create_project(project_name, "converter vector", "Vector") sa.create_annotation_classes_from_classes_json( project, out_dir + "/classes/classes.json" ) sa.upload_images_from_folder_to_project(project, out_dir) sa.upload_annotations_from_folder_to_project(project, out_dir) return 0
def test_nonrecursive_annotations_folder(tmpdir): tmpdir = Path(tmpdir) projects_found = sa.search_projects( TEMP_PROJECT_NAME + "0", return_metadata=True ) for pr in projects_found: sa.delete_project(pr) project = sa.create_project(TEMP_PROJECT_NAME + "0", "test", "Vector") sa.upload_images_from_folder_to_project( project, "./tests/sample_recursive_test", annotation_status="QualityCheck", recursive_subfolders=True ) assert len(sa.search_images(project)) == 2 sa.create_annotation_classes_from_classes_json( project, "./tests/sample_recursive_test/classes/classes.json" ) sa.upload_annotations_from_folder_to_project( project, "./tests/sample_recursive_test", recursive_subfolders=False ) export = sa.prepare_export(project) time.sleep(1) sa.download_export(project, export, tmpdir) non_empty_annotations = 0 json_files = tmpdir.glob("*.json") for json_file in json_files: json_ann = json.load(open(json_file)) if "instances" in json_ann and len(json_ann["instances"]) > 0: non_empty_annotations += 1 assert non_empty_annotations == 1
def test_add_bbox_noinit(tmpdir): tmpdir = Path(tmpdir) projects_found = sa.search_projects(PROJECT_NAME_NOINIT, return_metadata=True) for pr in projects_found: sa.delete_project(pr) project = sa.create_project(PROJECT_NAME_NOINIT, PROJECT_DESCRIPTION, "Vector") sa.upload_images_from_folder_to_project(project, PATH_TO_SAMPLE_PROJECT, annotation_status="InProgress") sa.create_annotation_classes_from_classes_json( project, PATH_TO_SAMPLE_PROJECT / "classes" / "classes.json") sa.create_annotation_class(project, "test_add", "#FF0000") images = sa.search_images(project, "example_image_1") image_name = images[0] sa.add_annotation_bbox_to_image(project, image_name, [10, 10, 500, 100], "test_add") sa.add_annotation_polygon_to_image(project, image_name, [100, 100, 500, 500, 200, 300], "test_add") annotations_new = sa.get_image_annotations(project, image_name)["annotation_json"] assert len(annotations_new["instances"]) == 2 export = sa.prepare_export(project, include_fuse=True) sa.download_export(project, export, tmpdir) non_empty_annotations = 0 json_files = tmpdir.glob("*.json") for json_file in json_files: json_ann = json.load(open(json_file)) if "instances" in json_ann and len(json_ann["instances"]) > 0: non_empty_annotations += 1 assert len(json_ann["instances"]) == 2 assert non_empty_annotations == 1
def test_pin_image_in_folder(tmpdir): tmpdir = Path(tmpdir) projects = sa.search_projects(PROJECT_NAME2, return_metadata=True) for project in projects: sa.delete_project(project) project = sa.create_project(PROJECT_NAME2, "test", "Vector") sa.create_folder(project, FOLDER2) project_folder = project["name"] + "/" + FOLDER2 sa.upload_images_from_folder_to_project(project_folder, "./tests/sample_project_vector", annotation_status="QualityCheck") img_metadata0 = sa.get_image_metadata(project_folder, "example_image_1.jpg") assert img_metadata0["is_pinned"] == 0 sa.pin_image(project_folder, "example_image_1.jpg") time.sleep(1) img_metadata = sa.get_image_metadata(project_folder, "example_image_1.jpg") assert img_metadata["is_pinned"] == 1 sa.pin_image(project_folder, "example_image_1.jpg", True) time.sleep(1) img_metadata = sa.get_image_metadata(project_folder, "example_image_1.jpg") assert img_metadata["is_pinned"] == 1 sa.pin_image(project_folder, "example_image_1.jpg", False) time.sleep(1) img_metadata = sa.get_image_metadata(project_folder, "example_image_1.jpg") assert img_metadata["is_pinned"] == 0 del img_metadata["updatedAt"] del img_metadata0["updatedAt"] assert img_metadata == img_metadata0
def test_preannotation_folder_upload_download(project_type, name, description, from_folder, tmpdir): projects_found = sa.search_projects(name, return_metadata=True) for pr in projects_found: sa.delete_project(pr) project = sa.create_project(name, description, project_type) sa.upload_images_from_folder_to_project(project, from_folder, annotation_status="InProgress") sa.create_annotation_classes_from_classes_json( project, from_folder / "classes" / "classes.json") sa.upload_preannotations_from_folder_to_project(project, from_folder) count_in = len(list(from_folder.glob("*.json"))) images = sa.search_images(project) for image_name in images: sa.download_image_preannotations(project, image_name, tmpdir) count_out = len(list(Path(tmpdir).glob("*.json"))) assert count_in == count_out
def test_sa_to_coco_to_sa(tmpdir): input_dir = Path("tests") / "sample_project_pixel" output1 = Path(tmpdir) / 'to_coco' output2 = Path(tmpdir) / 'to_sa' sa.export_annotation_format(input_dir, output1, "COCO", "object_test", "Pixel", "instance_segmentation", "Web") sa.import_annotation_format(output1, output2, "COCO", "object_test", "Pixel", "instance_segmentation", "Web", 'image_set') project_name = 'coco_pipeline_new' project = sa.search_projects(project_name, return_metadata=True) for pr in project: sa.delete_project(pr) project = sa.create_project(project_name, 'test_instane', 'Pixel') sa.upload_images_from_folder_to_project(project, output2) sa.create_annotation_classes_from_classes_json( project, output2 / "classes" / "classes.json") sa.upload_annotations_from_folder_to_project(project, output2)
def test_conversion(tmpdir): input_dir = Path( "tests" ) / "converter_test" / "COCO" / "input" / "fromSuperAnnotate" / "cats_dogs_vector_instance_segm" temp_dir = Path(tmpdir) / 'output_Desktop' final_dir = Path(tmpdir) / 'output_Web' sa.convert_platform(input_dir, temp_dir, "Web") sa.convert_platform(temp_dir, final_dir, "Desktop") init_gen = input_dir.glob('*.json') init_jsons = [file.name for file in init_gen] final_gen = final_dir.glob('*.json') final_jsons = [file.name for file in final_gen] assert set(init_jsons) == set(final_jsons) init_file_names = set( [file.replace('___objects.json', '') for file in init_jsons]) temp_file_names = set( json.load(open(temp_dir / 'annotations.json')).keys()) final_file_names = set( [file.replace('___objects.json', '') for file in final_jsons]) assert init_file_names == temp_file_names assert init_file_names == final_file_names project_name = "platform_conversion" projects = sa.search_projects(project_name, True) if projects: sa.delete_project(projects[0]) project = sa.create_project(project_name, "converter vector", "Vector") sa.create_annotation_classes_from_classes_json( project, final_dir / "classes" / "classes.json") sa.upload_images_from_folder_to_project(project, input_dir) sa.upload_annotations_from_folder_to_project(project, final_dir)
def test_annotations_recursive_s3_folder(tmpdir): tmpdir = Path(tmpdir) projects_found = sa.search_projects( TEMP_PROJECT_NAME + "4", return_metadata=True ) for pr in projects_found: sa.delete_project(pr) project = sa.create_project(TEMP_PROJECT_NAME + "4", "test", "Vector") sa.upload_images_from_folder_to_project( project, "sample_recursive_test", annotation_status="QualityCheck", from_s3_bucket="superannotate-python-sdk-test", recursive_subfolders=True ) assert len(sa.search_images(project)) == 2 sa.create_annotation_classes_from_classes_json( project, "sample_recursive_test/classes/classes.json", from_s3_bucket="superannotate-python-sdk-test" ) sa.upload_annotations_from_folder_to_project( project, "sample_recursive_test", recursive_subfolders=True, from_s3_bucket="superannotate-python-sdk-test" ) export = sa.prepare_export(project) time.sleep(1) sa.download_export(project, export, tmpdir) assert len(list(tmpdir.glob("*.json"))) == 2