def test_folder_export(tmpdir): PROJECT_NAME = "test folder export" tmpdir = Path(tmpdir) projects_found = sa.search_projects(PROJECT_NAME, return_metadata=True) for pr in projects_found: sa.delete_project(pr) project = sa.create_project(PROJECT_NAME, 'test', 'Vector') sa.create_annotation_classes_from_classes_json( project, FROM_FOLDER / "classes" / "classes.json") sa.upload_images_from_folder_to_project(project, FROM_FOLDER, annotation_status="InProgress") sa.create_folder(project, "folder1") project = PROJECT_NAME + "/folder1" sa.upload_images_from_folder_to_project(project, FROM_FOLDER, annotation_status="InProgress") sa.upload_annotations_from_folder_to_project(project, FROM_FOLDER) num_images = sa.get_project_image_count(project) assert num_images == 4 sa.create_folder(PROJECT_NAME, "folder2") project2 = PROJECT_NAME + "/folder2" num_images = sa.get_project_image_count(project2) assert num_images == 0 sa.copy_images(project, ["example_image_2.jpg", "example_image_3.jpg"], project2) export = sa.prepare_export(PROJECT_NAME, ["folder1", "folder2"]) sa.download_export(project, export, tmpdir) assert len(list((tmpdir / "classes").rglob("*"))) == 1 assert len(list((tmpdir / "folder1").rglob("*"))) == 4 assert len(list((tmpdir / "folder2").rglob("*"))) == 2 assert len(list((tmpdir).glob("*.*"))) == 0 export = sa.prepare_export(PROJECT_NAME) sa.download_export(project, export, tmpdir) assert len(list((tmpdir / "classes").rglob("*"))) == 1 assert len(list((tmpdir / "folder1").rglob("*"))) == 4 assert len(list((tmpdir / "folder2").rglob("*"))) == 2 assert len(list((tmpdir).glob("*.*"))) == 4
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) == 2 export = sa.prepare_export(project, include_fuse=True) sa.download_export(project, export, tmpdir) assert len(list(Path(tmpdir).rglob("*.*"))) == 4
def export_project(args): parser = argparse.ArgumentParser() parser.add_argument('--project', required=True, help='Project name to export') parser.add_argument('--folder', required=True, help='Folder to which export') parser.add_argument('--include-fuse', default=False, action='store_true', help='Enables fuse image export') parser.add_argument('--disable-extract-zip-contents', default=False, action='store_true', help='Disables export zip extraction') parser.add_argument( '--annotation-statuses', default=None, type=_list_str, help= 'List of image annotation statuses to include in export. Default is InProgress,QualityCheck,Returned,Completed' ) args = parser.parse_args(args) export = sa.prepare_export(args.project, args.annotation_statuses, args.include_fuse) sa.download_export(args.project, export, args.folder, not args.disable_extract_zip_contents)
def test_recursive_annotations_folder(tmpdir): tmpdir = Path(tmpdir) projects_found = sa.search_projects( TEMP_PROJECT_NAME + "1", return_metadata=True ) for pr in projects_found: sa.delete_project(pr) project = sa.create_project(TEMP_PROJECT_NAME + "1", "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=True ) export = sa.prepare_export(project) time.sleep(1) sa.download_export(project, export, tmpdir) assert len(list(tmpdir.glob("*.json"))) == 2
def test_basic_export(tmpdir): tmpdir = Path(tmpdir) projects_found = sa.search_projects(PROJECT_NAME, return_metadata=True) for pr in projects_found: sa.delete_project(pr) project = sa.create_project(PROJECT_NAME, "t", "Vector") sa.upload_images_from_folder_to_project( project, PROJECT_FOLDER, annotation_status="InProgress" ) len_orig = len(sa.search_images(project)) sa.create_annotation_classes_from_classes_json( project, PROJECT_FOLDER / "classes" / "classes.json" ) sa.upload_annotations_from_folder_to_project(project, PROJECT_FOLDER) export = sa.prepare_export(project, include_fuse=True) sa.download_export(project, export, tmpdir) projects_found = sa.search_projects( PROJECT_NAME + " import", return_metadata=True ) for pr in projects_found: sa.delete_project(pr) project_new = sa.create_project(PROJECT_NAME + " import", "f", "Vector") sa.upload_images_from_folder_to_project( project_new, tmpdir, annotation_status="InProgress" ) len_new = len(sa.search_images(project_new)) assert len_new == len_orig
def test_get_exports(tmpdir): tmpdir = Path(tmpdir) project = upload_project(PROJECT_FOLDER, PROJECT_NAME1, 'gg', 'Vector', annotation_status='QualityCheck') # projects_found = sa.search_projects(PROJECT_NAME1, return_metadata=True) # for pr in projects_found: # sa.delete_project(pr) # project = sa.create_project(PROJECT_NAME1, "gg", "Vector") # sa.upload_images_from_folder_to_project( # project, # "./tests/sample_project_vector/", # annotation_status="QualityCheck" # ) # sa.create_annotation_classes_from_classes_json( # project, # "./tests/sample_project_vector/classes/classes.json", # ) # sa.upload_annotations_from_folder_to_project( # project, # "./tests/sample_project_vector/", # ) exports_old = sa.get_exports(project) export = sa.prepare_export(project) sa.download_export(project, export["name"], tmpdir) js = list(tmpdir.glob("*.json")) assert len(js) == 4 exports_new = sa.get_exports(project) assert len(exports_new) == len(exports_old) + 1
def test_download_stress(tmpdir): project = sa.search_projects(name_prefix="test_test_15")[0] export = sa.prepare_export(project) sa.download_export(project, export, tmpdir) count_in_project = sa.get_project_image_count(project) count_in_folder = len(list(Path(tmpdir).glob("*.jpg"))) assert count_in_project == count_in_folder
def sa_download_files( project_name: str, destination: str = "./downloads", conf_path: object = "./config.json", ): sa.init(conf_path) export = sa.prepare_export(project_name, include_fuse=True) sa.download_export(project=project_name, export=export, folder_path=destination)
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) project = upload_project(Path("./tests/sample_project_vector"), PROJECT_NAME_EXPORT, 'test', 'Vector', annotation_status='InProgress') # 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 test_fuse_image_create_pixel(tmpdir): tmpdir = Path(tmpdir) projects = sa.search_projects(PROJECT_NAME_PIXEL, return_metadata=True) for project in projects: sa.delete_project(project) project = sa.create_project(PROJECT_NAME_PIXEL, "test", "Pixel") sa.upload_image_to_project( project, "./tests/sample_project_pixel/example_image_1.jpg", annotation_status="QualityCheck" ) sa.create_annotation_classes_from_classes_json( project, "./tests/sample_project_pixel/classes/classes.json" ) sa.upload_image_annotations( PROJECT_NAME_PIXEL, "example_image_1.jpg", "./tests/sample_project_pixel/example_image_1.jpg___pixel.json", "./tests/sample_project_pixel/example_image_1.jpg___save.png" ) export = sa.prepare_export(project, include_fuse=True) (tmpdir / "export").mkdir() sa.download_export(project, export, (tmpdir / "export")) # sa.create_fuse_image( # "./tests/sample_project_vector/example_image_1.jpg", # "./tests/sample_project_vector/classes/classes.json", "Vector" # ) paths = sa.download_image( project, "example_image_1.jpg", tmpdir, include_annotations=True, include_fuse=True ) print(paths, paths[2]) im1 = Image.open(tmpdir / "export" / "example_image_1.jpg___fuse.png") im1_array = np.array(im1) im2 = Image.open(paths[2][0]) im2_array = np.array(im2) assert im1_array.shape == im2_array.shape assert im1_array.dtype == im2_array.dtype assert np.array_equal(im1_array, im2_array)
def test_annotations_nonrecursive_s3_folder(tmpdir): tmpdir = Path(tmpdir) projects_found = sa.search_projects( TEMP_PROJECT_NAME + "5", return_metadata=True ) for pr in projects_found: sa.delete_project(pr) project = sa.create_project(TEMP_PROJECT_NAME + "5", "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=False, from_s3_bucket="superannotate-python-sdk-test" ) 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 export_project(command_name, args): parser = argparse.ArgumentParser(prog=_CLI_COMMAND + " " + command_name) parser.add_argument('--project', required=True, help='Project name to export') parser.add_argument('--folder', required=True, help='Folder to which export') parser.add_argument('--include-fuse', default=False, action='store_true', help='Enables fuse image export') parser.add_argument('--disable-extract-zip-contents', default=False, action='store_true', help='Disables export zip extraction') parser.add_argument( '--annotation-statuses', default=None, type=_list_str, help= 'List of image annotation statuses to include in export. Default is InProgress,QualityCheck,Returned,Completed' ) args = parser.parse_args(args) parts = args.project.split('/') if len(parts) == 1: project, project_folder = parts[0], None elif len(parts) == 2: project, project_folder = parts else: raise SABaseException( 0, "Project should be in format <project>[/<folder>]") export = sa.prepare_export( project, None if project_folder is None else [project_folder], annotation_statuses=args.annotation_statuses, include_fuse=args.include_fuse) sa.download_export(args.project, export, args.folder, not args.disable_extract_zip_contents)
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_meta_init(tmpdir): projects = sa.search_projects(name, return_metadata=True) for project in projects: sa.delete_project(project) project = sa.create_project(name, description, project_type) sa.upload_images_from_folder_to_project(project, from_folder, annotation_status="InProgress") for image in from_folder.glob("*.jpg"): size = cv2.imread(str(image)).shape annot = sa.get_image_annotations(project, image.name)["annotation_json"] print(annot) assert annot["metadata"]["width"] == size[1] assert annot["metadata"]["height"] == size[0] assert annot["metadata"]["name"] == image.name assert len(annot["metadata"]) == 3 sa.download_export(project, sa.prepare_export(project), tmpdir)
def test_get_exports(tmpdir): tmpdir = Path(tmpdir) projects_found = sa.search_projects(PROJECT_NAME, return_metadata=True) for pr in projects_found: sa.delete_project(pr) project = sa.create_project(PROJECT_NAME, "gg", "Vector") sa.upload_images_from_folder_to_project(project, "./tests/sample_project_vector/", annotation_status="QualityCheck") sa.create_annotation_classes_from_classes_json( project, "./tests/sample_project_vector/classes/classes.json", ) sa.upload_annotations_from_folder_to_project( project, "./tests/sample_project_vector/", ) export = sa.prepare_export(project) sa.download_export(project, export, tmpdir) js = list(tmpdir.glob("*.json")) assert len(js) == 4
def test_fuse_image_create_vector(tmpdir): tmpdir = Path(tmpdir) 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") sa.upload_image_to_project( project, "./tests/sample_project_vector/example_image_1.jpg", annotation_status="QualityCheck") sa.create_annotation_classes_from_classes_json( project, "./tests/sample_project_vector/classes/classes.json") sa.add_annotation_bbox_to_image(project, "example_image_1.jpg", [20, 20, 40, 40], "Human") sa.add_annotation_polygon_to_image(project, "example_image_1.jpg", [60, 60, 100, 100, 80, 100], "Personal vehicle") sa.add_annotation_polyline_to_image(project, "example_image_1.jpg", [200, 200, 300, 200, 350, 300], "Personal vehicle") sa.add_annotation_point_to_image(project, "example_image_1.jpg", [400, 400], "Personal vehicle") sa.add_annotation_ellipse_to_image(project, "example_image_1.jpg", [600, 600, 50, 100, 20], "Personal vehicle") sa.add_annotation_template_to_image( project, "example_image_1.jpg", [600, 300, 600, 350, 550, 250, 650, 250, 550, 400, 650, 400], [1, 2, 3, 1, 4, 1, 5, 2, 6, 2], "Human") sa.add_annotation_cuboid_to_image(project, "example_image_1.jpg", [60, 300, 200, 350, 120, 325, 250, 500], "Human") export = sa.prepare_export(project, include_fuse=True) (tmpdir / "export").mkdir() sa.download_export(project, export, (tmpdir / "export")) # sa.create_fuse_image( # "./tests/sample_project_vector/example_image_1.jpg", # "./tests/sample_project_vector/classes/classes.json", "Vector" # ) paths = sa.download_image(project, "example_image_1.jpg", tmpdir, include_annotations=True, include_fuse=True, include_overlay=True) im1 = Image.open(tmpdir / "export" / "example_image_1.jpg___fuse.png") im1_array = np.array(im1) im2 = Image.open(paths[2][0]) im2_array = np.array(im2) assert im1_array.shape == im2_array.shape assert im1_array.dtype == im2_array.dtype
def test_add_bbox(tmpdir): tmpdir = Path(tmpdir) projects_found = sa.search_projects(PROJECT_NAME, return_metadata=True) for pr in projects_found: if pr["name"] == PROJECT_NAME: sa.delete_project(pr) project = sa.create_project(PROJECT_NAME, PROJECT_DESCRIPTION, "Vector") sa.upload_images_from_folder_to_project(PROJECT_NAME, 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", [{ "name": "height", "attributes": [{ "name": "tall" }, { "name": "short" }] }]) sa.upload_annotations_from_folder_to_project(project, PATH_TO_SAMPLE_PROJECT) images = sa.search_images(project, "example_image_1") image_name = images[0] annotations = sa.get_image_annotations(project, image_name)["annotation_json"] sa.add_annotation_bbox_to_image(project, image_name, [10, 10, 500, 100], "test_add") sa.add_annotation_polyline_to_image(project, image_name, [110, 110, 510, 510, 600, 510], "test_add") sa.add_annotation_polygon_to_image(project, image_name, [100, 100, 500, 500, 200, 300], "test_add", [{ "name": "tall", "groupName": "height" }]) sa.add_annotation_point_to_image(project, image_name, [250, 250], "test_add") sa.add_annotation_ellipse_to_image(project, image_name, [405, 405, 20, 70, 15], "test_add") sa.add_annotation_template_to_image(project, image_name, [600, 30, 630, 30, 615, 60], [1, 3, 2, 3], "test_add") sa.add_annotation_cuboid_to_image(project, image_name, [800, 500, 900, 600, 850, 450, 950, 700], "test_add") sa.add_annotation_comment_to_image(project, image_name, "hey", [100, 100], "*****@*****.**", True) annotations_new = sa.get_image_annotations(project, image_name)["annotation_json"] json.dump(annotations_new, open(tmpdir / "new_anns.json", "w")) assert len(annotations_new["instances"]) + len( annotations_new["comments"]) == len(annotations["instances"]) + len( annotations["comments"]) + 8 export = sa.prepare_export(project, include_fuse=True) sa.download_export(project, export, tmpdir) df = sa.aggregate_annotations_as_df(tmpdir) print(df) print(image_name) num = len( df[df["imageName"] == image_name]["instanceId"].dropna().unique()) assert num == len( annotations["instances"] ) - 3 + 7 # -6 for 3 comments and 3 invalid annotations, className or attributes
def test_basic_project(project_type, name, description, from_folder, tmpdir): tmpdir = Path(tmpdir) projects_found = sa.search_projects(name, return_metadata=True) for pr in projects_found: sa.delete_project(pr) projects_found = sa.search_projects(name, return_metadata=True) assert len(projects_found) == 0 project = sa.create_project(name, description, project_type) assert project["name"] == name assert project["description"] == description assert project["type"] == project_type projects_found = sa.search_projects(name) assert len(projects_found) == 1 assert projects_found[0] == name sa.upload_images_from_folder_to_project(project, from_folder, annotation_status="InProgress") count_in_folder = len(list(from_folder.glob("*.jpg"))) + len( list(from_folder.glob("*.png"))) count_in_folder -= len(list(from_folder.glob("*___fuse.png"))) if project_type == "Pixel": count_in_folder -= len(list(from_folder.glob("*___save.png"))) images = sa.search_images(project) assert count_in_folder == len(images) sa.create_annotation_classes_from_classes_json( project, from_folder / "classes" / "classes.json") classes_in_file = json.load(open(from_folder / "classes" / "classes.json")) classes_in_project = sa.search_annotation_classes(project) json.dump(classes_in_project, open(Path(tmpdir) / "tmp_c.json", 'w')) assert len(classes_in_file) == len(classes_in_project) for cl_f in classes_in_file: found = False for cl_c in classes_in_project: if cl_f["name"] == cl_c["name"]: found = True break assert found sa.upload_annotations_from_folder_to_project(project, from_folder) export = sa.prepare_export(project) sa.download_export(project, export, tmpdir) for image in from_folder.glob("*.[jpg|png]"): found = False for image_in_project in tmpdir.glob("*.jpg"): if image.name == image_in_project.name: found = True break assert found, image for json_in_folder in from_folder.glob("*.json"): found = False for json_in_project in tmpdir.glob("*.json"): if json_in_folder.name == json_in_project.name: found = True break assert found, json_in_folder if project_type == "Pixel": for mask_in_folder in from_folder.glob("*___save.png"): found = False for mask_in_project in tmpdir.glob("*___save.png"): if mask_in_folder.name == mask_in_project.name: found = True break assert found, mask_in_folder