superannotate 4.4.25.dev2__tar.gz → 4.4.26.dev1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {superannotate-4.4.25.dev2/src/superannotate.egg-info → superannotate-4.4.26.dev1}/PKG-INFO +1 -1
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/__init__.py +2 -2
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/interface/sdk_interface.py +62 -27
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/entities/project.py +1 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/enums.py +1 -1
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/service_types.py +5 -1
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/serviceproviders.py +25 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/usecases/annotations.py +9 -24
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/usecases/images.py +6 -13
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/usecases/items.py +149 -1
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/usecases/models.py +4 -1
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/infrastructure/controller.py +55 -18
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/infrastructure/serviceprovider.py +18 -2
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/infrastructure/services/http_client.py +6 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/infrastructure/services/item.py +58 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/infrastructure/services/work_management.py +41 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/infrastructure/stream_data_handler.py +25 -11
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1/src/superannotate.egg-info}/PKG-INFO +1 -1
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/LICENSE +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/MANIFEST.in +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/README.rst +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/requirements.txt +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/setup.cfg +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/setup.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/__init__.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/__init__.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/analytics/__init__.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/analytics/aggregators.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/analytics/common.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/bin/__init__.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/bin/superannotate.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/common.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/exceptions.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/helpers.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/__init__.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/conversion.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/__init__.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/baseStrategy.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/coco_converters/__init__.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/coco_converters/coco_api.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/coco_converters/coco_converter.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/coco_converters/coco_strategies.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/coco_converters/coco_to_sa_pixel.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/coco_converters/coco_to_sa_vector.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/coco_converters/sa_pixel_to_coco.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/coco_converters/sa_vector_to_coco.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/converters.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/dataloop_converters/__init__.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/dataloop_converters/dataloop_helper.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/dataloop_converters/dataloop_strategies.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/dataloop_converters/dataloop_to_sa_vector.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/googlecloud_converters/__init__.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/googlecloud_converters/googlecloud_strategies.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/googlecloud_converters/googlecloud_to_sa_vector.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/labelbox_converters/__init__.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/labelbox_converters/labelbox_helper.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/labelbox_converters/labelbox_strategies.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/labelbox_converters/labelbox_to_sa_pixel.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/labelbox_converters/labelbox_to_sa_vector.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/sa_json_helper.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/sagemaker_converters/__init__.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/sagemaker_converters/sagemaker_strategies.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/sagemaker_converters/sagemaker_to_sa_pixel.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/sagemaker_converters/sagemaker_to_sa_vector.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/supervisely_converters/__init__.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/supervisely_converters/supervisely_helper.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/supervisely_converters/supervisely_strategies.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/supervisely_converters/supervisely_to_sa_pixel.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/supervisely_converters/supervisely_to_sa_vector.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/vgg_converters/__init__.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/vgg_converters/vgg_helper.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/vgg_converters/vgg_strategies.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/vgg_converters/vgg_to_sa_vector.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/voc_converters/__init__.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/voc_converters/voc_helper.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/voc_converters/voc_strategies.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/voc_converters/voc_to_sa_pixel.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/voc_converters/voc_to_sa_vector.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/vott_converters/__init__.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/vott_converters/vott_strategies.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/vott_converters/vott_to_sa_vector.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/yolo_converters/__init__.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/yolo_converters/yolo_strategies.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/converters/yolo_converters/yolo_to_sa_vector.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/export_from_sa_conversions.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/import_to_sa_conversions.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/input_converters/sa_conversion.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/interface/__init__.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/interface/base_interface.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/interface/cli_interface.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/interface/sdk/__init__.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/interface/sdk/folders.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/interface/sdk/project.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/interface/types.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/app/serializers.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/__init__.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/base_usecases.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/conditions.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/config.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/entities/__init__.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/entities/base.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/entities/classes.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/entities/folder.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/entities/integrations.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/entities/items.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/entities/project_entities.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/exceptions.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/jsx_conditions.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/plugin.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/pydantic_v1.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/reporter.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/repositories.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/response.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/types.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/usecases/__init__.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/usecases/base.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/usecases/classes.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/usecases/custom_fields.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/usecases/folders.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/usecases/integrations.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/usecases/projects.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/video_convertor.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/infrastructure/__init__.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/infrastructure/helpers.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/infrastructure/repositories.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/infrastructure/services/__init__.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/infrastructure/services/annotation.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/infrastructure/services/annotation_class.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/infrastructure/services/explore.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/infrastructure/services/folder.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/infrastructure/services/integration.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/infrastructure/services/item_service.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/infrastructure/services/project.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/infrastructure/utils.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/infrastructure/validators.py +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate.egg-info/SOURCES.txt +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate.egg-info/dependency_links.txt +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate.egg-info/entry_points.txt +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate.egg-info/requires.txt +0 -0
- {superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate.egg-info/top_level.txt +0 -0
|
@@ -3,7 +3,7 @@ import os
|
|
|
3
3
|
import sys
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
__version__ = "4.4.
|
|
6
|
+
__version__ = "4.4.26dev1"
|
|
7
7
|
|
|
8
8
|
os.environ.update({"sa_version": __version__})
|
|
9
9
|
sys.path.append(os.path.split(os.path.realpath(__file__))[0])
|
|
@@ -18,7 +18,7 @@ from lib.core.exceptions import AppException
|
|
|
18
18
|
from lib.app.input_converters import convert_project_type
|
|
19
19
|
from lib.app.input_converters import export_annotation
|
|
20
20
|
from lib.app.input_converters import import_annotation
|
|
21
|
-
from lib.app.interface.sdk_interface import SAClient
|
|
21
|
+
from superannotate.lib.app.interface.sdk_interface import SAClient
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
SESSIONS = {}
|
|
@@ -79,7 +79,7 @@ PROJECT_TYPE = Literal[
|
|
|
79
79
|
"Document",
|
|
80
80
|
"Tiled",
|
|
81
81
|
"PointCloud",
|
|
82
|
-
"
|
|
82
|
+
"Multimodal",
|
|
83
83
|
]
|
|
84
84
|
|
|
85
85
|
|
|
@@ -307,7 +307,7 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
|
|
|
307
307
|
:param project_description: the new project's description
|
|
308
308
|
:type project_description: str
|
|
309
309
|
|
|
310
|
-
:param project_type: the new project type, Vector, Pixel, Video, Document, Tiled, PointCloud,
|
|
310
|
+
:param project_type: the new project type, Vector, Pixel, Video, Document, Tiled, PointCloud, Multimodal.
|
|
311
311
|
:type project_type: str
|
|
312
312
|
|
|
313
313
|
:param settings: list of settings objects
|
|
@@ -711,8 +711,8 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
|
|
|
711
711
|
"""
|
|
712
712
|
warnings.warn(
|
|
713
713
|
DeprecationWarning(
|
|
714
|
-
"The “
|
|
715
|
-
" Please use the “
|
|
714
|
+
"The “get_project_workflow” function is deprecated."
|
|
715
|
+
" Please use the “get_project_steps” function instead."
|
|
716
716
|
)
|
|
717
717
|
)
|
|
718
718
|
return self.get_project_steps(project)
|
|
@@ -1215,11 +1215,11 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
|
|
|
1215
1215
|
:param only_pinned: enable only pinned output in export. This option disables all other types of output.
|
|
1216
1216
|
:type only_pinned: bool
|
|
1217
1217
|
|
|
1218
|
-
:param kwargs:
|
|
1219
|
-
Arbitrary kwargs:
|
|
1218
|
+
:param kwargs: Arbitrary keyword arguments:
|
|
1220
1219
|
|
|
1221
|
-
- integration_name:
|
|
1222
|
-
- format:
|
|
1220
|
+
- integration_name: The name of the integration within the platform that is being used.
|
|
1221
|
+
- format: The format in which the data will be exported in multimodal projects.
|
|
1222
|
+
It can be either CSV or JSON. If None, the data will be exported in the default JSON format.
|
|
1223
1223
|
:return: metadata object of the prepared export
|
|
1224
1224
|
:rtype: dict
|
|
1225
1225
|
|
|
@@ -1232,7 +1232,7 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
|
|
|
1232
1232
|
project = "Project Name",
|
|
1233
1233
|
folder_names = ["Folder 1", "Folder 2"],
|
|
1234
1234
|
annotation_statuses = ["Completed","QualityCheck"],
|
|
1235
|
-
|
|
1235
|
+
format = "CSV"
|
|
1236
1236
|
)
|
|
1237
1237
|
|
|
1238
1238
|
client.download_export("Project Name", export, "path_to_download")
|
|
@@ -2318,7 +2318,7 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
|
|
|
2318
2318
|
|
|
2319
2319
|
def get_annotations(
|
|
2320
2320
|
self,
|
|
2321
|
-
project: Union[
|
|
2321
|
+
project: Union[NotEmptyStr, int],
|
|
2322
2322
|
items: Optional[Union[List[NotEmptyStr], List[int]]] = None,
|
|
2323
2323
|
):
|
|
2324
2324
|
"""Returns annotations for the given list of items.
|
|
@@ -2663,29 +2663,28 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
|
|
|
2663
2663
|
|
|
2664
2664
|
def list_items(
|
|
2665
2665
|
self,
|
|
2666
|
-
project: Union[
|
|
2667
|
-
folder: Optional[Union[
|
|
2666
|
+
project: Union[NotEmptyStr, int],
|
|
2667
|
+
folder: Optional[Union[NotEmptyStr, int]] = None,
|
|
2668
2668
|
*,
|
|
2669
|
-
include: List[Literal["
|
|
2669
|
+
include: List[Literal["custom_metadata"]] = None,
|
|
2670
2670
|
**filters,
|
|
2671
2671
|
):
|
|
2672
2672
|
"""
|
|
2673
2673
|
Search items by filtering criteria.
|
|
2674
2674
|
|
|
2675
|
-
:param project: The project name, project ID, or folder path (e.g., "project1
|
|
2675
|
+
:param project: The project name, project ID, or folder path (e.g., "project1") to search within.
|
|
2676
2676
|
This can refer to the root of the project or a specific subfolder.
|
|
2677
|
-
:type project: Union[
|
|
2677
|
+
:type project: Union[NotEmptyStr, int]
|
|
2678
2678
|
|
|
2679
2679
|
:param folder: The folder name or ID to search within. If None, the search will be done in the root folder of
|
|
2680
2680
|
the project. If both “project” and “folder” specify folders, the “project”
|
|
2681
2681
|
value will take priority.
|
|
2682
|
-
:type folder: Union[
|
|
2682
|
+
:type folder: Union[NotEmptyStr, int], optional
|
|
2683
2683
|
|
|
2684
2684
|
:param include: Specifies additional fields to include in the response.
|
|
2685
2685
|
|
|
2686
2686
|
Possible values are
|
|
2687
2687
|
|
|
2688
|
-
- "assignee": Includes information about the role of the item assignee.
|
|
2689
2688
|
- "custom_metadata": Includes custom metadata attached to the item.
|
|
2690
2689
|
:type include: list of str, optional
|
|
2691
2690
|
|
|
@@ -2695,8 +2694,8 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
|
|
|
2695
2694
|
|
|
2696
2695
|
|
|
2697
2696
|
Supported operations:
|
|
2698
|
-
- __ne: Value is
|
|
2699
|
-
- __in: Value is
|
|
2697
|
+
- __ne: Value is not equal.
|
|
2698
|
+
- __in: Value is in the list.
|
|
2700
2699
|
- __notin: Value is not in the list.
|
|
2701
2700
|
- __contains: Value has the substring.
|
|
2702
2701
|
- __starts: Value starts with the prefix.
|
|
@@ -2711,6 +2710,9 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
|
|
|
2711
2710
|
- name__contains: str
|
|
2712
2711
|
- name__starts: str
|
|
2713
2712
|
- name__ends: str
|
|
2713
|
+
- annotation_status: str
|
|
2714
|
+
- annotation_status__in: list[str]
|
|
2715
|
+
- annotation_status__ne: list[str]
|
|
2714
2716
|
- approval_status: Literal["Approved", "Disapproved", None]
|
|
2715
2717
|
- assignments__user_id: str
|
|
2716
2718
|
- assignments__user_id__ne: str
|
|
@@ -2801,8 +2803,6 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
|
|
|
2801
2803
|
if include:
|
|
2802
2804
|
if "custom_metadata" not in include:
|
|
2803
2805
|
exclude.add("custom_metadata")
|
|
2804
|
-
if "assignments" not in include:
|
|
2805
|
-
exclude.add("assignments")
|
|
2806
2806
|
return BaseSerializer.serialize_iterable(res, exclude=exclude)
|
|
2807
2807
|
|
|
2808
2808
|
def attach_items(
|
|
@@ -2930,26 +2930,46 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
|
|
|
2930
2930
|
source: Union[NotEmptyStr, dict],
|
|
2931
2931
|
destination: Union[NotEmptyStr, dict],
|
|
2932
2932
|
items: Optional[List[NotEmptyStr]] = None,
|
|
2933
|
-
include_annotations:
|
|
2933
|
+
include_annotations: bool = True,
|
|
2934
|
+
duplicate_strategy: Literal[
|
|
2935
|
+
"skip", "replace", "replace_annotations_only"
|
|
2936
|
+
] = "skip",
|
|
2934
2937
|
):
|
|
2935
2938
|
"""Copy images in bulk between folders in a project
|
|
2936
2939
|
|
|
2937
|
-
:param source: project name or folder path to
|
|
2940
|
+
:param source: project name (root) or folder path to pick items from (e.g., “project1/folder1”).
|
|
2938
2941
|
:type source: str
|
|
2939
2942
|
|
|
2940
|
-
:param destination: project name (root) or folder path to place copied items.
|
|
2943
|
+
:param destination: project name (root) or folder path to place copied items (e.g., “project1/folder2”).
|
|
2941
2944
|
:type destination: str
|
|
2942
2945
|
|
|
2943
2946
|
:param items: names of items to copy. If None, all items from the source directory will be copied.
|
|
2944
2947
|
:type items: list of str
|
|
2945
2948
|
|
|
2946
|
-
:param include_annotations: enables annotations
|
|
2949
|
+
:param include_annotations: enables the copying of item data, including annotations, status, priority score,
|
|
2950
|
+
approval state, and category. If set to False, only the items will be copied without additional data.
|
|
2947
2951
|
:type include_annotations: bool
|
|
2948
2952
|
|
|
2953
|
+
:param duplicate_strategy: Specifies the strategy for handling duplicate items in the destination.
|
|
2954
|
+
The default value is "skip".
|
|
2955
|
+
|
|
2956
|
+
- "skip": skips duplicate items in the destination and continues with the next item.
|
|
2957
|
+
- "replace": replaces the annotations, status, priority score, approval state, and category of duplicate items.
|
|
2958
|
+
- "replace_annotations_only": replaces only the annotations of duplicate items,
|
|
2959
|
+
leaving other data (status, priority score, approval state, and category) unchanged.
|
|
2960
|
+
|
|
2961
|
+
:type duplicate_strategy: Literal["skip", "replace", "replace_annotations_only"]
|
|
2962
|
+
|
|
2949
2963
|
:return: list of skipped item names
|
|
2950
2964
|
:rtype: list of strs
|
|
2951
2965
|
"""
|
|
2952
2966
|
|
|
2967
|
+
if not include_annotations and duplicate_strategy != "skip":
|
|
2968
|
+
duplicate_strategy = "skip"
|
|
2969
|
+
logger.warning(
|
|
2970
|
+
"Copy operation continuing without annotations and metadata due to include_annotations=False."
|
|
2971
|
+
)
|
|
2972
|
+
|
|
2953
2973
|
project_name, source_folder = extract_project_folder(source)
|
|
2954
2974
|
to_project_name, destination_folder = extract_project_folder(destination)
|
|
2955
2975
|
if project_name != to_project_name:
|
|
@@ -2963,6 +2983,7 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
|
|
|
2963
2983
|
to_folder=to_folder,
|
|
2964
2984
|
item_names=items,
|
|
2965
2985
|
include_annotations=include_annotations,
|
|
2986
|
+
duplicate_strategy=duplicate_strategy,
|
|
2966
2987
|
)
|
|
2967
2988
|
if response.errors:
|
|
2968
2989
|
raise AppException(response.errors)
|
|
@@ -2974,18 +2995,31 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
|
|
|
2974
2995
|
source: Union[NotEmptyStr, dict],
|
|
2975
2996
|
destination: Union[NotEmptyStr, dict],
|
|
2976
2997
|
items: Optional[List[NotEmptyStr]] = None,
|
|
2998
|
+
duplicate_strategy: Literal[
|
|
2999
|
+
"skip", "replace", "replace_annotations_only"
|
|
3000
|
+
] = "skip",
|
|
2977
3001
|
):
|
|
2978
3002
|
"""Move images in bulk between folders in a project
|
|
2979
3003
|
|
|
2980
|
-
:param source: project name or folder path to pick items from (e.g., “project1/folder1”).
|
|
3004
|
+
:param source: project name (root) or folder path to pick items from (e.g., “project1/folder1”).
|
|
2981
3005
|
:type source: str
|
|
2982
3006
|
|
|
2983
|
-
:param destination: project name (root) or folder path to move items to.
|
|
3007
|
+
:param destination: project name (root) or folder path to move items to (e.g., “project1/folder2”).
|
|
2984
3008
|
:type destination: str
|
|
2985
3009
|
|
|
2986
3010
|
:param items: names of items to move. If None, all items from the source directory will be moved.
|
|
2987
3011
|
:type items: list of str
|
|
2988
3012
|
|
|
3013
|
+
:param duplicate_strategy: Specifies the strategy for handling duplicate items in the destination.
|
|
3014
|
+
The default value is "skip".
|
|
3015
|
+
|
|
3016
|
+
- "skip": skips duplicate items in the destination and continues with the next item.
|
|
3017
|
+
- "replace": replaces the annotations, status, priority score, approval state, and category of duplicate items.
|
|
3018
|
+
- "replace_annotations_only": replaces only the annotations of duplicate items,
|
|
3019
|
+
leaving other data (status, priority score, approval state, and category) unchanged.
|
|
3020
|
+
|
|
3021
|
+
:type duplicate_strategy: Literal["skip", "replace", "replace_annotations_only"]
|
|
3022
|
+
|
|
2989
3023
|
:return: list of skipped item names
|
|
2990
3024
|
:rtype: list of strs
|
|
2991
3025
|
"""
|
|
@@ -3003,6 +3037,7 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
|
|
|
3003
3037
|
from_folder=source_folder,
|
|
3004
3038
|
to_folder=destination_folder,
|
|
3005
3039
|
item_names=items,
|
|
3040
|
+
duplicate_strategy=duplicate_strategy,
|
|
3006
3041
|
)
|
|
3007
3042
|
if response.errors:
|
|
3008
3043
|
raise AppException(response.errors)
|
|
@@ -108,7 +108,7 @@ class ProjectType(BaseTitledEnum):
|
|
|
108
108
|
TILED = "Tiled", 5
|
|
109
109
|
OTHER = "Other", 6
|
|
110
110
|
POINT_CLOUD = "PointCloud", 7
|
|
111
|
-
|
|
111
|
+
MULTIMODAL = "Multimodal", 8
|
|
112
112
|
UNSUPPORTED_TYPE_1 = "UnsupportedType", 9
|
|
113
113
|
UNSUPPORTED_TYPE_2 = "UnsupportedType", 10
|
|
114
114
|
|
{superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/service_types.py
RENAMED
|
@@ -222,6 +222,10 @@ class ProjectResponse(ServiceResponse):
|
|
|
222
222
|
res_data: entities.ProjectEntity = None
|
|
223
223
|
|
|
224
224
|
|
|
225
|
+
class WorkflowResponse(ServiceResponse):
|
|
226
|
+
res_data: entities.WorkflowEntity = None
|
|
227
|
+
|
|
228
|
+
|
|
225
229
|
class WorkflowListResponse(ServiceResponse):
|
|
226
230
|
res_data: List[entities.WorkflowEntity] = None
|
|
227
231
|
|
|
@@ -242,5 +246,5 @@ PROJECT_TYPE_RESPONSE_MAP = {
|
|
|
242
246
|
ProjectType.PIXEL: ImageResponse,
|
|
243
247
|
ProjectType.DOCUMENT: DocumentResponse,
|
|
244
248
|
ProjectType.POINT_CLOUD: PointCloudResponse,
|
|
245
|
-
ProjectType.
|
|
249
|
+
ProjectType.MULTIMODAL: ImageResponse,
|
|
246
250
|
}
|
|
@@ -5,6 +5,7 @@ from typing import Any
|
|
|
5
5
|
from typing import Callable
|
|
6
6
|
from typing import Dict
|
|
7
7
|
from typing import List
|
|
8
|
+
from typing import Literal
|
|
8
9
|
|
|
9
10
|
from lib.core import entities
|
|
10
11
|
from lib.core.conditions import Condition
|
|
@@ -70,6 +71,10 @@ class SuperannotateServiceProvider(ABC):
|
|
|
70
71
|
|
|
71
72
|
|
|
72
73
|
class BaseWorkManagementService(SuperannotateServiceProvider):
|
|
74
|
+
@abstractmethod
|
|
75
|
+
def get_workflow(self, pk: int) -> entities.WorkflowEntity:
|
|
76
|
+
raise NotImplementedError
|
|
77
|
+
|
|
73
78
|
@abstractmethod
|
|
74
79
|
def list_workflows(self, query: Query) -> WorkflowListResponse:
|
|
75
80
|
raise NotImplementedError
|
|
@@ -283,10 +288,30 @@ class BaseItemService(SuperannotateServiceProvider):
|
|
|
283
288
|
) -> ServiceResponse:
|
|
284
289
|
raise NotImplementedError
|
|
285
290
|
|
|
291
|
+
@abstractmethod
|
|
292
|
+
def copy_move_multiple(
|
|
293
|
+
self,
|
|
294
|
+
project: entities.ProjectEntity,
|
|
295
|
+
from_folder: entities.FolderEntity,
|
|
296
|
+
to_folder: entities.FolderEntity,
|
|
297
|
+
item_names: List[str],
|
|
298
|
+
duplicate_strategy: Literal["skip", "replace", "replace_annotations_only"],
|
|
299
|
+
operation: Literal["copy", "move"],
|
|
300
|
+
include_annotations: bool = True,
|
|
301
|
+
include_pin: bool = False,
|
|
302
|
+
) -> ServiceResponse:
|
|
303
|
+
raise NotImplementedError
|
|
304
|
+
|
|
286
305
|
@abstractmethod
|
|
287
306
|
def await_copy(self, project: entities.ProjectEntity, poll_id: int, items_count):
|
|
288
307
|
raise NotImplementedError
|
|
289
308
|
|
|
309
|
+
@abstractmethod
|
|
310
|
+
def await_copy_move(
|
|
311
|
+
self, project: entities.ProjectEntity, poll_id: int, items_count
|
|
312
|
+
):
|
|
313
|
+
raise NotImplementedError
|
|
314
|
+
|
|
290
315
|
@abstractmethod
|
|
291
316
|
def set_statuses(
|
|
292
317
|
self,
|
|
@@ -36,7 +36,6 @@ from lib.core.entities import FolderEntity
|
|
|
36
36
|
from lib.core.entities import ImageEntity
|
|
37
37
|
from lib.core.entities import ProjectEntity
|
|
38
38
|
from lib.core.entities import UserEntity
|
|
39
|
-
from lib.core.entities import WorkflowEntity
|
|
40
39
|
from lib.core.exceptions import AppException
|
|
41
40
|
from lib.core.jsx_conditions import EmptyQuery
|
|
42
41
|
from lib.core.jsx_conditions import Filter
|
|
@@ -477,13 +476,8 @@ class UploadAnnotationsUseCase(BaseReportableUseCase):
|
|
|
477
476
|
{i.item.name for i in items_to_upload}
|
|
478
477
|
- set(self._report.failed_annotations).union(set(skipped))
|
|
479
478
|
)
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
)
|
|
483
|
-
if not response.ok:
|
|
484
|
-
raise AppException(response.error)
|
|
485
|
-
workflow: WorkflowEntity = next(
|
|
486
|
-
(i for i in response.data if i.id == self._project.workflow_id), None
|
|
479
|
+
workflow = self._service_provider.work_management.get_workflow(
|
|
480
|
+
self._project.workflow_id
|
|
487
481
|
)
|
|
488
482
|
if workflow.is_system():
|
|
489
483
|
if uploaded_annotations and not self._keep_status:
|
|
@@ -842,13 +836,10 @@ class UploadAnnotationsFromFolderUseCase(BaseReportableUseCase):
|
|
|
842
836
|
name_path_mappings.keys()
|
|
843
837
|
- set(self._report.failed_annotations).union(set(missing_annotations))
|
|
844
838
|
)
|
|
845
|
-
|
|
846
|
-
|
|
839
|
+
workflow = self._service_provider.work_management.get_workflow(
|
|
840
|
+
self._project.workflow_id
|
|
847
841
|
)
|
|
848
|
-
if
|
|
849
|
-
raise response.error
|
|
850
|
-
workflow = response.data[0]
|
|
851
|
-
if workflow.is_system and uploaded_annotations and not self._keep_status:
|
|
842
|
+
if workflow.is_system() and uploaded_annotations and not self._keep_status:
|
|
852
843
|
statuses_changed = set_annotation_statuses_in_progress(
|
|
853
844
|
service_provider=self._service_provider,
|
|
854
845
|
project=self._project,
|
|
@@ -1084,13 +1075,10 @@ class UploadAnnotationUseCase(BaseReportableUseCase):
|
|
|
1084
1075
|
],
|
|
1085
1076
|
Body=mask,
|
|
1086
1077
|
)
|
|
1087
|
-
|
|
1088
|
-
|
|
1078
|
+
workflow = self._service_provider.work_management.get_workflow(
|
|
1079
|
+
self._project.workflow_id
|
|
1089
1080
|
)
|
|
1090
|
-
if not
|
|
1091
|
-
raise AppException(response.error)
|
|
1092
|
-
workflow = response.data[0]
|
|
1093
|
-
if workflow.is_system and not self._keep_status:
|
|
1081
|
+
if workflow.is_system() and not self._keep_status:
|
|
1094
1082
|
statuses_changed = set_annotation_statuses_in_progress(
|
|
1095
1083
|
service_provider=self._service_provider,
|
|
1096
1084
|
project=self._project,
|
|
@@ -1426,11 +1414,8 @@ class ValidateAnnotationUseCase(BaseReportableUseCase):
|
|
|
1426
1414
|
schema_response = self._service_provider.annotations.get_schema(
|
|
1427
1415
|
self._project_type, version
|
|
1428
1416
|
)
|
|
1429
|
-
if not schema_response.ok:
|
|
1417
|
+
if not schema_response.ok or not schema_response.data:
|
|
1430
1418
|
raise AppException(f"Schema {version} does not exist.")
|
|
1431
|
-
if not schema_response.data:
|
|
1432
|
-
ValidateAnnotationUseCase.SCHEMAS[key] = lambda x: x
|
|
1433
|
-
return ValidateAnnotationUseCase.SCHEMAS[key]
|
|
1434
1419
|
validator = superannotate_schemas.Draft7Validator(schema_response.data)
|
|
1435
1420
|
from functools import partial
|
|
1436
1421
|
|
|
@@ -743,19 +743,15 @@ class UploadImageToProject(BaseUseCase):
|
|
|
743
743
|
self._s3_repo = s3_repo
|
|
744
744
|
self._service_provider = service_provider
|
|
745
745
|
if annotation_status_value is None:
|
|
746
|
-
|
|
747
|
-
|
|
746
|
+
workflow = self._service_provider.work_management.get_workflow(
|
|
747
|
+
self._project.workflow_id
|
|
748
748
|
)
|
|
749
|
-
if
|
|
750
|
-
raise AppException(response.error)
|
|
751
|
-
workflow = response.data[0]
|
|
752
|
-
if workflow.is_system:
|
|
749
|
+
if workflow.is_system():
|
|
753
750
|
annotation_status_value = (
|
|
754
751
|
self._service_provider.get_annotation_status_value(
|
|
755
752
|
self._project, "NotStarted"
|
|
756
753
|
)
|
|
757
754
|
)
|
|
758
|
-
|
|
759
755
|
self._annotation_status_value = annotation_status_value
|
|
760
756
|
self._auth_data = None
|
|
761
757
|
|
|
@@ -1106,13 +1102,10 @@ class UploadImagesToProject(BaseInteractiveUseCase):
|
|
|
1106
1102
|
attach_duplications_list = []
|
|
1107
1103
|
|
|
1108
1104
|
if not self._annotation_status_value:
|
|
1109
|
-
|
|
1110
|
-
|
|
1105
|
+
workflow = self._service_provider.work_management.get_workflow(
|
|
1106
|
+
self._project.workflow_id
|
|
1111
1107
|
)
|
|
1112
|
-
if
|
|
1113
|
-
raise AppException(response.error)
|
|
1114
|
-
workflow = response.data[0]
|
|
1115
|
-
if workflow.is_system:
|
|
1108
|
+
if workflow.is_system():
|
|
1116
1109
|
self._annotation_status_value = (
|
|
1117
1110
|
self._service_provider.get_annotation_status_value(
|
|
1118
1111
|
self._project, "NotStarted"
|
{superannotate-4.4.25.dev2 → superannotate-4.4.26.dev1}/src/superannotate/lib/core/usecases/items.py
RENAMED
|
@@ -33,6 +33,7 @@ from lib.core.usecases.base import BaseUseCase
|
|
|
33
33
|
from lib.core.usecases.folders import SearchFoldersUseCase
|
|
34
34
|
from lib.infrastructure.utils import divide_to_chunks
|
|
35
35
|
from lib.infrastructure.utils import extract_project_folder
|
|
36
|
+
from typing_extensions import Literal
|
|
36
37
|
|
|
37
38
|
logger = logging.getLogger("sa")
|
|
38
39
|
|
|
@@ -537,6 +538,154 @@ class MoveItems(BaseReportableUseCase):
|
|
|
537
538
|
return self._response
|
|
538
539
|
|
|
539
540
|
|
|
541
|
+
class CopyMoveItems(BaseReportableUseCase):
|
|
542
|
+
"""
|
|
543
|
+
Copy/Move items in bulk between folders in a project.
|
|
544
|
+
Return skipped item names.
|
|
545
|
+
"""
|
|
546
|
+
|
|
547
|
+
def __init__(
|
|
548
|
+
self,
|
|
549
|
+
reporter: Reporter,
|
|
550
|
+
project: ProjectEntity,
|
|
551
|
+
from_folder: FolderEntity,
|
|
552
|
+
to_folder: FolderEntity,
|
|
553
|
+
item_names: List[str],
|
|
554
|
+
service_provider: BaseServiceProvider,
|
|
555
|
+
include_annotations: bool,
|
|
556
|
+
duplicate_strategy: Literal["skip", "replace", "replace_annotations_only"],
|
|
557
|
+
operation: Literal["copy", "move"],
|
|
558
|
+
chunk_size: int = 1000,
|
|
559
|
+
):
|
|
560
|
+
super().__init__(reporter)
|
|
561
|
+
self._project = project
|
|
562
|
+
self._from_folder = from_folder
|
|
563
|
+
self._to_folder = to_folder
|
|
564
|
+
self._item_names = item_names
|
|
565
|
+
self._service_provider = service_provider
|
|
566
|
+
self._include_annotations = include_annotations
|
|
567
|
+
self._duplicate_strategy = duplicate_strategy
|
|
568
|
+
self._operation = operation
|
|
569
|
+
self._chunk_size = chunk_size
|
|
570
|
+
|
|
571
|
+
def _validate_limitations(self, items_count):
|
|
572
|
+
response = self._service_provider.get_limitations(
|
|
573
|
+
project=self._project,
|
|
574
|
+
folder=self._to_folder,
|
|
575
|
+
)
|
|
576
|
+
if not response.ok:
|
|
577
|
+
raise AppValidationException(response.error)
|
|
578
|
+
if self._operation == "copy":
|
|
579
|
+
folder_limit_err_msg = constants.COPY_FOLDER_LIMIT_ERROR_MESSAGE
|
|
580
|
+
project_limit_err_msg = constants.COPY_PROJECT_LIMIT_ERROR_MESSAGE
|
|
581
|
+
else:
|
|
582
|
+
folder_limit_err_msg = constants.MOVE_FOLDER_LIMIT_ERROR_MESSAGE
|
|
583
|
+
project_limit_err_msg = constants.MOVE_PROJECT_LIMIT_ERROR_MESSAGE
|
|
584
|
+
if items_count > response.data.folder_limit.remaining_image_count:
|
|
585
|
+
raise AppValidationException(folder_limit_err_msg)
|
|
586
|
+
if items_count > response.data.project_limit.remaining_image_count:
|
|
587
|
+
raise AppValidationException(project_limit_err_msg)
|
|
588
|
+
|
|
589
|
+
def validate_item_names(self):
|
|
590
|
+
if self._item_names:
|
|
591
|
+
self._item_names = list(set(self._item_names))
|
|
592
|
+
|
|
593
|
+
def execute(self):
|
|
594
|
+
if self.is_valid():
|
|
595
|
+
if self._item_names:
|
|
596
|
+
items = self._item_names
|
|
597
|
+
else:
|
|
598
|
+
res = self._service_provider.item_service.list(
|
|
599
|
+
self._project.id, self._from_folder.id, EmptyQuery()
|
|
600
|
+
)
|
|
601
|
+
if res.error:
|
|
602
|
+
raise AppException(res.error)
|
|
603
|
+
items = [i.name for i in res.data]
|
|
604
|
+
try:
|
|
605
|
+
self._validate_limitations(len(items))
|
|
606
|
+
except AppValidationException as e:
|
|
607
|
+
self._response.errors = e
|
|
608
|
+
return self._response
|
|
609
|
+
skipped_items = []
|
|
610
|
+
if self._duplicate_strategy == "skip":
|
|
611
|
+
existing_items = []
|
|
612
|
+
for i in range(0, len(items), self._chunk_size):
|
|
613
|
+
query = Filter(
|
|
614
|
+
"name", items[i : i + self._chunk_size], OperatorEnum.IN
|
|
615
|
+
) # noqa
|
|
616
|
+
res = self._service_provider.item_service.list(
|
|
617
|
+
self._project.id, self._to_folder.id, query
|
|
618
|
+
)
|
|
619
|
+
if res.error:
|
|
620
|
+
raise AppException(res.error)
|
|
621
|
+
if not res.data:
|
|
622
|
+
continue
|
|
623
|
+
existing_items += res.data
|
|
624
|
+
duplications = [item.name for item in existing_items]
|
|
625
|
+
items_to_processing = list(set(items) - set(duplications))
|
|
626
|
+
skipped_items.extend(duplications)
|
|
627
|
+
else:
|
|
628
|
+
items_to_processing = items
|
|
629
|
+
if items_to_processing:
|
|
630
|
+
for i in range(0, len(items_to_processing), self._chunk_size):
|
|
631
|
+
chunk_to_process = items_to_processing[
|
|
632
|
+
i : i + self._chunk_size
|
|
633
|
+
] # noqa: E203
|
|
634
|
+
response = self._service_provider.items.copy_move_multiple(
|
|
635
|
+
project=self._project,
|
|
636
|
+
from_folder=self._from_folder,
|
|
637
|
+
to_folder=self._to_folder,
|
|
638
|
+
item_names=chunk_to_process,
|
|
639
|
+
include_annotations=self._include_annotations,
|
|
640
|
+
duplicate_strategy=self._duplicate_strategy,
|
|
641
|
+
operation=self._operation,
|
|
642
|
+
)
|
|
643
|
+
if not response.ok or not response.data.get("poll_id"):
|
|
644
|
+
skipped_items.extend(chunk_to_process)
|
|
645
|
+
continue
|
|
646
|
+
try:
|
|
647
|
+
self._service_provider.items.await_copy_move(
|
|
648
|
+
project=self._project,
|
|
649
|
+
poll_id=response.data["poll_id"],
|
|
650
|
+
items_count=len(chunk_to_process),
|
|
651
|
+
)
|
|
652
|
+
except BackendError as e:
|
|
653
|
+
self._response.errors = AppException(e)
|
|
654
|
+
return self._response
|
|
655
|
+
existing_items = []
|
|
656
|
+
for i in range(0, len(items_to_processing), self._chunk_size):
|
|
657
|
+
res = self._service_provider.item_service.list(
|
|
658
|
+
self._project.id,
|
|
659
|
+
self._to_folder.id,
|
|
660
|
+
Filter(
|
|
661
|
+
"name",
|
|
662
|
+
items_to_processing[i : i + self._chunk_size],
|
|
663
|
+
OperatorEnum.IN,
|
|
664
|
+
), # noqa
|
|
665
|
+
)
|
|
666
|
+
if res.error:
|
|
667
|
+
raise AppException(res.error)
|
|
668
|
+
|
|
669
|
+
existing_items += res.data
|
|
670
|
+
|
|
671
|
+
existing_item_names_set = {item.name for item in existing_items}
|
|
672
|
+
items_to_processing_names_set = set(items_to_processing)
|
|
673
|
+
processed_items = existing_item_names_set.intersection(
|
|
674
|
+
items_to_processing_names_set
|
|
675
|
+
)
|
|
676
|
+
skipped_items.extend(
|
|
677
|
+
list(items_to_processing_names_set - processed_items)
|
|
678
|
+
)
|
|
679
|
+
operation_processing_map = {"copy": "Copied", "move": "Moved"}
|
|
680
|
+
self.reporter.log_info(
|
|
681
|
+
f"{operation_processing_map[self._operation]} {len(processed_items)}/{len(items_to_processing)} item(s) from "
|
|
682
|
+
f"{self._project.name}{'' if self._from_folder.is_root else f'/{self._from_folder.name}'} to "
|
|
683
|
+
f"{self._project.name}{'' if self._to_folder.is_root else f'/{self._to_folder.name}'}"
|
|
684
|
+
)
|
|
685
|
+
self._response.data = list(set(skipped_items))
|
|
686
|
+
return self._response
|
|
687
|
+
|
|
688
|
+
|
|
540
689
|
class SetAnnotationStatues(BaseReportableUseCase):
|
|
541
690
|
CHUNK_SIZE = 500
|
|
542
691
|
ERROR_MESSAGE = "Failed to change status"
|
|
@@ -926,7 +1075,6 @@ class AddItemsToSubsetUseCase(BaseUseCase):
|
|
|
926
1075
|
self,
|
|
927
1076
|
):
|
|
928
1077
|
if self.is_valid():
|
|
929
|
-
|
|
930
1078
|
futures = []
|
|
931
1079
|
with ThreadPoolExecutor(max_workers=4) as executor:
|
|
932
1080
|
for path, items in self.path_separated.items():
|
|
@@ -82,7 +82,10 @@ class PrepareExportUseCase(BaseUseCase):
|
|
|
82
82
|
raise AppValidationException(
|
|
83
83
|
"COCO format is not supported for this project."
|
|
84
84
|
)
|
|
85
|
-
elif
|
|
85
|
+
elif (
|
|
86
|
+
self._export_type == 3
|
|
87
|
+
and self._project.type != ProjectType.MULTIMODAL.value
|
|
88
|
+
):
|
|
86
89
|
raise AppValidationException(
|
|
87
90
|
"CSV format is not supported for this project."
|
|
88
91
|
)
|