label-studio-sdk 0.0.34__py3-none-any.whl → 1.0.1__py3-none-any.whl
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.
Potentially problematic release.
This version of label-studio-sdk might be problematic. Click here for more details.
- label_studio_sdk/__init__.py +232 -9
- label_studio_sdk/_extensions/label_studio_tools/__init__.py +0 -0
- label_studio_sdk/_extensions/label_studio_tools/core/__init__.py +0 -0
- label_studio_sdk/_extensions/label_studio_tools/core/label_config.py +163 -0
- label_studio_sdk/_extensions/label_studio_tools/core/utils/__init__.py +0 -0
- label_studio_sdk/_extensions/label_studio_tools/core/utils/exceptions.py +2 -0
- label_studio_sdk/_extensions/label_studio_tools/core/utils/io.py +228 -0
- label_studio_sdk/_extensions/label_studio_tools/core/utils/params.py +45 -0
- label_studio_sdk/_extensions/label_studio_tools/etl/__init__.py +1 -0
- label_studio_sdk/_extensions/label_studio_tools/etl/beam.py +34 -0
- label_studio_sdk/_extensions/label_studio_tools/etl/example.py +17 -0
- label_studio_sdk/_extensions/label_studio_tools/etl/registry.py +67 -0
- label_studio_sdk/_extensions/label_studio_tools/postprocessing/__init__.py +0 -0
- label_studio_sdk/_extensions/label_studio_tools/postprocessing/video.py +97 -0
- label_studio_sdk/_extensions/pager_ext.py +49 -0
- label_studio_sdk/_legacy/__init__.py +11 -0
- label_studio_sdk/_legacy/client.py +471 -0
- label_studio_sdk/_legacy/objects.py +74 -0
- label_studio_sdk/{project.py → _legacy/project.py} +2 -2
- label_studio_sdk/{schema → _legacy/schema}/label_config_schema.json +14 -14
- label_studio_sdk/actions/__init__.py +27 -0
- label_studio_sdk/actions/client.py +223 -0
- label_studio_sdk/actions/types/__init__.py +25 -0
- label_studio_sdk/actions/types/actions_create_request_filters.py +43 -0
- label_studio_sdk/actions/types/actions_create_request_filters_conjunction.py +5 -0
- label_studio_sdk/actions/types/actions_create_request_filters_items_item.py +49 -0
- label_studio_sdk/actions/types/actions_create_request_filters_items_item_filter.py +31 -0
- label_studio_sdk/actions/types/actions_create_request_filters_items_item_operator.py +23 -0
- label_studio_sdk/actions/types/actions_create_request_id.py +19 -0
- label_studio_sdk/actions/types/actions_create_request_ordering_item.py +31 -0
- label_studio_sdk/actions/types/actions_create_request_selected_items.py +10 -0
- label_studio_sdk/actions/types/actions_create_request_selected_items_excluded.py +39 -0
- label_studio_sdk/actions/types/actions_create_request_selected_items_included.py +39 -0
- label_studio_sdk/annotations/__init__.py +2 -0
- label_studio_sdk/annotations/client.py +750 -0
- label_studio_sdk/base_client.py +183 -0
- label_studio_sdk/client.py +17 -463
- label_studio_sdk/converter/__init__.py +7 -0
- label_studio_sdk/converter/audio.py +56 -0
- label_studio_sdk/converter/brush.py +452 -0
- label_studio_sdk/converter/converter.py +1175 -0
- label_studio_sdk/converter/exports/__init__.py +0 -0
- label_studio_sdk/converter/exports/csv.py +82 -0
- label_studio_sdk/converter/exports/csv2.py +103 -0
- label_studio_sdk/converter/funsd.py +85 -0
- label_studio_sdk/converter/imports/__init__.py +0 -0
- label_studio_sdk/converter/imports/coco.py +314 -0
- label_studio_sdk/converter/imports/colors.py +198 -0
- label_studio_sdk/converter/imports/label_config.py +45 -0
- label_studio_sdk/converter/imports/pathtrack.py +269 -0
- label_studio_sdk/converter/imports/yolo.py +236 -0
- label_studio_sdk/converter/main.py +202 -0
- label_studio_sdk/converter/utils.py +473 -0
- label_studio_sdk/core/__init__.py +33 -0
- label_studio_sdk/core/api_error.py +15 -0
- label_studio_sdk/core/client_wrapper.py +55 -0
- label_studio_sdk/core/datetime_utils.py +28 -0
- label_studio_sdk/core/file.py +38 -0
- label_studio_sdk/core/http_client.py +447 -0
- label_studio_sdk/core/jsonable_encoder.py +99 -0
- label_studio_sdk/core/pagination.py +87 -0
- label_studio_sdk/core/pydantic_utilities.py +28 -0
- label_studio_sdk/core/query_encoder.py +33 -0
- label_studio_sdk/core/remove_none_from_dict.py +11 -0
- label_studio_sdk/core/request_options.py +32 -0
- label_studio_sdk/environment.py +7 -0
- label_studio_sdk/errors/__init__.py +6 -0
- label_studio_sdk/errors/bad_request_error.py +8 -0
- label_studio_sdk/errors/internal_server_error.py +8 -0
- label_studio_sdk/export_storage/__init__.py +28 -0
- label_studio_sdk/export_storage/azure/__init__.py +5 -0
- label_studio_sdk/export_storage/azure/client.py +888 -0
- label_studio_sdk/export_storage/azure/types/__init__.py +6 -0
- label_studio_sdk/export_storage/azure/types/azure_create_response.py +67 -0
- label_studio_sdk/export_storage/azure/types/azure_update_response.py +67 -0
- label_studio_sdk/export_storage/client.py +107 -0
- label_studio_sdk/export_storage/gcs/__init__.py +5 -0
- label_studio_sdk/export_storage/gcs/client.py +888 -0
- label_studio_sdk/export_storage/gcs/types/__init__.py +6 -0
- label_studio_sdk/export_storage/gcs/types/gcs_create_response.py +67 -0
- label_studio_sdk/export_storage/gcs/types/gcs_update_response.py +67 -0
- label_studio_sdk/export_storage/local/__init__.py +5 -0
- label_studio_sdk/export_storage/local/client.py +834 -0
- label_studio_sdk/export_storage/local/types/__init__.py +6 -0
- label_studio_sdk/export_storage/local/types/local_create_response.py +57 -0
- label_studio_sdk/export_storage/local/types/local_update_response.py +57 -0
- label_studio_sdk/export_storage/redis/__init__.py +5 -0
- label_studio_sdk/export_storage/redis/client.py +918 -0
- label_studio_sdk/export_storage/redis/types/__init__.py +6 -0
- label_studio_sdk/export_storage/redis/types/redis_create_response.py +72 -0
- label_studio_sdk/export_storage/redis/types/redis_update_response.py +72 -0
- label_studio_sdk/export_storage/s3/__init__.py +5 -0
- label_studio_sdk/export_storage/s3/client.py +1008 -0
- label_studio_sdk/export_storage/s3/types/__init__.py +6 -0
- label_studio_sdk/export_storage/s3/types/s3create_response.py +89 -0
- label_studio_sdk/export_storage/s3/types/s3update_response.py +89 -0
- label_studio_sdk/export_storage/types/__init__.py +5 -0
- label_studio_sdk/export_storage/types/export_storage_list_types_response_item.py +30 -0
- label_studio_sdk/files/__init__.py +2 -0
- label_studio_sdk/files/client.py +556 -0
- label_studio_sdk/import_storage/__init__.py +28 -0
- label_studio_sdk/import_storage/azure/__init__.py +5 -0
- label_studio_sdk/import_storage/azure/client.py +988 -0
- label_studio_sdk/import_storage/azure/types/__init__.py +6 -0
- label_studio_sdk/import_storage/azure/types/azure_create_response.py +82 -0
- label_studio_sdk/import_storage/azure/types/azure_update_response.py +82 -0
- label_studio_sdk/import_storage/client.py +107 -0
- label_studio_sdk/import_storage/gcs/__init__.py +5 -0
- label_studio_sdk/import_storage/gcs/client.py +988 -0
- label_studio_sdk/import_storage/gcs/types/__init__.py +6 -0
- label_studio_sdk/import_storage/gcs/types/gcs_create_response.py +82 -0
- label_studio_sdk/import_storage/gcs/types/gcs_update_response.py +82 -0
- label_studio_sdk/import_storage/local/__init__.py +5 -0
- label_studio_sdk/import_storage/local/client.py +836 -0
- label_studio_sdk/import_storage/local/types/__init__.py +6 -0
- label_studio_sdk/import_storage/local/types/local_create_response.py +57 -0
- label_studio_sdk/import_storage/local/types/local_update_response.py +57 -0
- label_studio_sdk/import_storage/redis/__init__.py +5 -0
- label_studio_sdk/import_storage/redis/client.py +924 -0
- label_studio_sdk/import_storage/redis/types/__init__.py +6 -0
- label_studio_sdk/import_storage/redis/types/redis_create_response.py +72 -0
- label_studio_sdk/import_storage/redis/types/redis_update_response.py +72 -0
- label_studio_sdk/import_storage/s3/__init__.py +5 -0
- label_studio_sdk/import_storage/s3/client.py +1138 -0
- label_studio_sdk/import_storage/s3/types/__init__.py +6 -0
- label_studio_sdk/import_storage/s3/types/s3create_response.py +109 -0
- label_studio_sdk/import_storage/s3/types/s3update_response.py +109 -0
- label_studio_sdk/import_storage/types/__init__.py +5 -0
- label_studio_sdk/import_storage/types/import_storage_list_types_response_item.py +30 -0
- label_studio_sdk/label_interface/base.py +10 -0
- label_studio_sdk/label_interface/control_tags.py +109 -71
- label_studio_sdk/label_interface/data_examples.json +96 -0
- label_studio_sdk/label_interface/interface.py +102 -53
- label_studio_sdk/label_interface/object_tags.py +8 -13
- label_studio_sdk/label_interface/region.py +33 -1
- label_studio_sdk/ml/__init__.py +19 -0
- label_studio_sdk/ml/client.py +981 -0
- label_studio_sdk/ml/types/__init__.py +17 -0
- label_studio_sdk/ml/types/ml_create_request_auth_method.py +5 -0
- label_studio_sdk/ml/types/ml_create_response.py +78 -0
- label_studio_sdk/ml/types/ml_create_response_auth_method.py +5 -0
- label_studio_sdk/ml/types/ml_update_request_auth_method.py +5 -0
- label_studio_sdk/ml/types/ml_update_response.py +78 -0
- label_studio_sdk/ml/types/ml_update_response_auth_method.py +5 -0
- label_studio_sdk/predictions/__init__.py +2 -0
- label_studio_sdk/predictions/client.py +638 -0
- label_studio_sdk/projects/__init__.py +6 -0
- label_studio_sdk/projects/client.py +1055 -0
- label_studio_sdk/projects/client_ext.py +19 -0
- label_studio_sdk/projects/exports/__init__.py +2 -0
- label_studio_sdk/projects/exports/client.py +930 -0
- label_studio_sdk/projects/types/__init__.py +7 -0
- label_studio_sdk/projects/types/projects_create_response.py +96 -0
- label_studio_sdk/projects/types/projects_import_tasks_response.py +71 -0
- label_studio_sdk/projects/types/projects_list_response.py +33 -0
- label_studio_sdk/py.typed +0 -0
- label_studio_sdk/tasks/__init__.py +5 -0
- label_studio_sdk/tasks/client.py +835 -0
- label_studio_sdk/tasks/client_ext.py +18 -0
- label_studio_sdk/tasks/types/__init__.py +6 -0
- label_studio_sdk/tasks/types/tasks_list_request_fields.py +5 -0
- label_studio_sdk/tasks/types/tasks_list_response.py +48 -0
- label_studio_sdk/types/__init__.py +115 -0
- label_studio_sdk/types/annotation.py +116 -0
- label_studio_sdk/types/annotation_filter_options.py +42 -0
- label_studio_sdk/types/annotation_last_action.py +19 -0
- label_studio_sdk/types/azure_blob_export_storage.py +112 -0
- label_studio_sdk/types/azure_blob_export_storage_status.py +7 -0
- label_studio_sdk/types/azure_blob_import_storage.py +113 -0
- label_studio_sdk/types/azure_blob_import_storage_status.py +7 -0
- label_studio_sdk/types/base_task.py +113 -0
- label_studio_sdk/types/base_user.py +42 -0
- label_studio_sdk/types/converted_format.py +36 -0
- label_studio_sdk/types/converted_format_status.py +5 -0
- label_studio_sdk/types/export.py +48 -0
- label_studio_sdk/types/export_convert.py +32 -0
- label_studio_sdk/types/export_create.py +54 -0
- label_studio_sdk/types/export_create_status.py +5 -0
- label_studio_sdk/types/export_status.py +5 -0
- label_studio_sdk/types/file_upload.py +30 -0
- label_studio_sdk/types/filter.py +53 -0
- label_studio_sdk/types/filter_group.py +35 -0
- label_studio_sdk/types/gcs_export_storage.py +112 -0
- label_studio_sdk/types/gcs_export_storage_status.py +7 -0
- label_studio_sdk/types/gcs_import_storage.py +113 -0
- label_studio_sdk/types/gcs_import_storage_status.py +7 -0
- label_studio_sdk/types/local_files_export_storage.py +97 -0
- label_studio_sdk/types/local_files_export_storage_status.py +7 -0
- label_studio_sdk/types/local_files_import_storage.py +92 -0
- label_studio_sdk/types/local_files_import_storage_status.py +7 -0
- label_studio_sdk/types/ml_backend.py +89 -0
- label_studio_sdk/types/ml_backend_auth_method.py +5 -0
- label_studio_sdk/types/ml_backend_state.py +5 -0
- label_studio_sdk/types/prediction.py +78 -0
- label_studio_sdk/types/project.py +198 -0
- label_studio_sdk/types/project_import.py +63 -0
- label_studio_sdk/types/project_import_status.py +5 -0
- label_studio_sdk/types/project_label_config.py +32 -0
- label_studio_sdk/types/project_sampling.py +7 -0
- label_studio_sdk/types/project_skip_queue.py +5 -0
- label_studio_sdk/types/redis_export_storage.py +117 -0
- label_studio_sdk/types/redis_export_storage_status.py +7 -0
- label_studio_sdk/types/redis_import_storage.py +112 -0
- label_studio_sdk/types/redis_import_storage_status.py +7 -0
- label_studio_sdk/types/s3export_storage.py +134 -0
- label_studio_sdk/types/s3export_storage_status.py +7 -0
- label_studio_sdk/types/s3import_storage.py +140 -0
- label_studio_sdk/types/s3import_storage_status.py +7 -0
- label_studio_sdk/types/serialization_option.py +36 -0
- label_studio_sdk/types/serialization_options.py +45 -0
- label_studio_sdk/types/task.py +157 -0
- label_studio_sdk/types/task_filter_options.py +49 -0
- label_studio_sdk/types/user_simple.py +37 -0
- label_studio_sdk/types/view.py +55 -0
- label_studio_sdk/types/webhook.py +67 -0
- label_studio_sdk/types/webhook_actions_item.py +21 -0
- label_studio_sdk/types/webhook_serializer_for_update.py +67 -0
- label_studio_sdk/types/webhook_serializer_for_update_actions_item.py +21 -0
- label_studio_sdk/users/__init__.py +5 -0
- label_studio_sdk/users/client.py +830 -0
- label_studio_sdk/users/types/__init__.py +6 -0
- label_studio_sdk/users/types/users_get_token_response.py +36 -0
- label_studio_sdk/users/types/users_reset_token_response.py +36 -0
- label_studio_sdk/version.py +4 -0
- label_studio_sdk/views/__init__.py +35 -0
- label_studio_sdk/views/client.py +564 -0
- label_studio_sdk/views/types/__init__.py +33 -0
- label_studio_sdk/views/types/views_create_request_data.py +43 -0
- label_studio_sdk/views/types/views_create_request_data_filters.py +43 -0
- label_studio_sdk/views/types/views_create_request_data_filters_conjunction.py +5 -0
- label_studio_sdk/views/types/views_create_request_data_filters_items_item.py +49 -0
- label_studio_sdk/views/types/views_create_request_data_filters_items_item_filter.py +31 -0
- label_studio_sdk/views/types/views_create_request_data_filters_items_item_operator.py +23 -0
- label_studio_sdk/views/types/views_create_request_data_ordering_item.py +31 -0
- label_studio_sdk/views/types/views_update_request_data.py +43 -0
- label_studio_sdk/views/types/views_update_request_data_filters.py +43 -0
- label_studio_sdk/views/types/views_update_request_data_filters_conjunction.py +5 -0
- label_studio_sdk/views/types/views_update_request_data_filters_items_item.py +49 -0
- label_studio_sdk/views/types/views_update_request_data_filters_items_item_filter.py +31 -0
- label_studio_sdk/views/types/views_update_request_data_filters_items_item_operator.py +23 -0
- label_studio_sdk/views/types/views_update_request_data_ordering_item.py +31 -0
- label_studio_sdk/webhooks/__init__.py +5 -0
- label_studio_sdk/webhooks/client.py +636 -0
- label_studio_sdk/webhooks/types/__init__.py +5 -0
- label_studio_sdk/webhooks/types/webhooks_update_request_actions_item.py +21 -0
- label_studio_sdk-1.0.1.dist-info/METADATA +163 -0
- label_studio_sdk-1.0.1.dist-info/RECORD +256 -0
- {label_studio_sdk-0.0.34.dist-info → label_studio_sdk-1.0.1.dist-info}/WHEEL +1 -2
- label_studio_sdk/objects.py +0 -35
- label_studio_sdk-0.0.34.dist-info/LICENSE +0 -201
- label_studio_sdk-0.0.34.dist-info/METADATA +0 -24
- label_studio_sdk-0.0.34.dist-info/RECORD +0 -37
- label_studio_sdk-0.0.34.dist-info/top_level.txt +0 -2
- tests/test_client.py +0 -37
- tests/test_export.py +0 -105
- tests/test_interface/__init__.py +0 -1
- tests/test_interface/configs.py +0 -137
- tests/test_interface/mockups.py +0 -22
- tests/test_interface/test_compat.py +0 -64
- tests/test_interface/test_control_tags.py +0 -55
- tests/test_interface/test_data_generation.py +0 -45
- tests/test_interface/test_lpi.py +0 -15
- tests/test_interface/test_main.py +0 -196
- tests/test_interface/test_object_tags.py +0 -36
- tests/test_interface/test_region.py +0 -36
- tests/test_interface/test_validate_summary.py +0 -35
- tests/test_interface/test_validation.py +0 -59
- {tests → label_studio_sdk/_extensions}/__init__.py +0 -0
- /label_studio_sdk/{exceptions.py → _legacy/exceptions.py} +0 -0
- /label_studio_sdk/{users.py → _legacy/users.py} +0 -0
- /label_studio_sdk/{utils.py → _legacy/utils.py} +0 -0
- /label_studio_sdk/{workspaces.py → _legacy/workspaces.py} +0 -0
label_studio_sdk/__init__.py
CHANGED
|
@@ -1,11 +1,234 @@
|
|
|
1
|
-
|
|
2
|
-
"""
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
|
3
2
|
|
|
4
|
-
from .
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
from .types import (
|
|
4
|
+
Annotation,
|
|
5
|
+
AnnotationFilterOptions,
|
|
6
|
+
AnnotationLastAction,
|
|
7
|
+
AzureBlobExportStorage,
|
|
8
|
+
AzureBlobExportStorageStatus,
|
|
9
|
+
AzureBlobImportStorage,
|
|
10
|
+
AzureBlobImportStorageStatus,
|
|
11
|
+
BaseTask,
|
|
12
|
+
BaseUser,
|
|
13
|
+
ConvertedFormat,
|
|
14
|
+
ConvertedFormatStatus,
|
|
15
|
+
Export,
|
|
16
|
+
ExportConvert,
|
|
17
|
+
ExportCreate,
|
|
18
|
+
ExportCreateStatus,
|
|
19
|
+
ExportStatus,
|
|
20
|
+
FileUpload,
|
|
21
|
+
Filter,
|
|
22
|
+
FilterGroup,
|
|
23
|
+
GcsExportStorage,
|
|
24
|
+
GcsExportStorageStatus,
|
|
25
|
+
GcsImportStorage,
|
|
26
|
+
GcsImportStorageStatus,
|
|
27
|
+
LocalFilesExportStorage,
|
|
28
|
+
LocalFilesExportStorageStatus,
|
|
29
|
+
LocalFilesImportStorage,
|
|
30
|
+
LocalFilesImportStorageStatus,
|
|
31
|
+
MlBackend,
|
|
32
|
+
MlBackendAuthMethod,
|
|
33
|
+
MlBackendState,
|
|
34
|
+
Prediction,
|
|
35
|
+
Project,
|
|
36
|
+
ProjectImport,
|
|
37
|
+
ProjectImportStatus,
|
|
38
|
+
ProjectLabelConfig,
|
|
39
|
+
ProjectSampling,
|
|
40
|
+
ProjectSkipQueue,
|
|
41
|
+
RedisExportStorage,
|
|
42
|
+
RedisExportStorageStatus,
|
|
43
|
+
RedisImportStorage,
|
|
44
|
+
RedisImportStorageStatus,
|
|
45
|
+
S3ExportStorage,
|
|
46
|
+
S3ExportStorageStatus,
|
|
47
|
+
S3ImportStorage,
|
|
48
|
+
S3ImportStorageStatus,
|
|
49
|
+
SerializationOption,
|
|
50
|
+
SerializationOptions,
|
|
51
|
+
Task,
|
|
52
|
+
TaskFilterOptions,
|
|
53
|
+
UserSimple,
|
|
54
|
+
View,
|
|
55
|
+
Webhook,
|
|
56
|
+
WebhookActionsItem,
|
|
57
|
+
WebhookSerializerForUpdate,
|
|
58
|
+
WebhookSerializerForUpdateActionsItem,
|
|
59
|
+
)
|
|
60
|
+
from .errors import BadRequestError, InternalServerError
|
|
61
|
+
from . import (
|
|
62
|
+
actions,
|
|
63
|
+
annotations,
|
|
64
|
+
export_storage,
|
|
65
|
+
files,
|
|
66
|
+
import_storage,
|
|
67
|
+
ml,
|
|
68
|
+
predictions,
|
|
69
|
+
projects,
|
|
70
|
+
tasks,
|
|
71
|
+
users,
|
|
72
|
+
views,
|
|
73
|
+
webhooks,
|
|
74
|
+
)
|
|
75
|
+
from ._legacy import Client
|
|
76
|
+
from .actions import (
|
|
77
|
+
ActionsCreateRequestFilters,
|
|
78
|
+
ActionsCreateRequestFiltersConjunction,
|
|
79
|
+
ActionsCreateRequestFiltersItemsItem,
|
|
80
|
+
ActionsCreateRequestFiltersItemsItemFilter,
|
|
81
|
+
ActionsCreateRequestFiltersItemsItemOperator,
|
|
82
|
+
ActionsCreateRequestId,
|
|
83
|
+
ActionsCreateRequestOrderingItem,
|
|
84
|
+
ActionsCreateRequestSelectedItems,
|
|
85
|
+
ActionsCreateRequestSelectedItemsExcluded,
|
|
86
|
+
ActionsCreateRequestSelectedItemsIncluded,
|
|
87
|
+
)
|
|
88
|
+
from .environment import LabelStudioEnvironment
|
|
89
|
+
from .export_storage import ExportStorageListTypesResponseItem
|
|
90
|
+
from .import_storage import ImportStorageListTypesResponseItem
|
|
91
|
+
from .ml import (
|
|
92
|
+
MlCreateRequestAuthMethod,
|
|
93
|
+
MlCreateResponse,
|
|
94
|
+
MlCreateResponseAuthMethod,
|
|
95
|
+
MlUpdateRequestAuthMethod,
|
|
96
|
+
MlUpdateResponse,
|
|
97
|
+
MlUpdateResponseAuthMethod,
|
|
98
|
+
)
|
|
99
|
+
from .projects import ProjectsCreateResponse, ProjectsImportTasksResponse, ProjectsListResponse
|
|
100
|
+
from .tasks import TasksListRequestFields, TasksListResponse
|
|
101
|
+
from .users import UsersGetTokenResponse, UsersResetTokenResponse
|
|
102
|
+
from .version import __version__
|
|
103
|
+
from .views import (
|
|
104
|
+
ViewsCreateRequestData,
|
|
105
|
+
ViewsCreateRequestDataFilters,
|
|
106
|
+
ViewsCreateRequestDataFiltersConjunction,
|
|
107
|
+
ViewsCreateRequestDataFiltersItemsItem,
|
|
108
|
+
ViewsCreateRequestDataFiltersItemsItemFilter,
|
|
109
|
+
ViewsCreateRequestDataFiltersItemsItemOperator,
|
|
110
|
+
ViewsCreateRequestDataOrderingItem,
|
|
111
|
+
ViewsUpdateRequestData,
|
|
112
|
+
ViewsUpdateRequestDataFilters,
|
|
113
|
+
ViewsUpdateRequestDataFiltersConjunction,
|
|
114
|
+
ViewsUpdateRequestDataFiltersItemsItem,
|
|
115
|
+
ViewsUpdateRequestDataFiltersItemsItemFilter,
|
|
116
|
+
ViewsUpdateRequestDataFiltersItemsItemOperator,
|
|
117
|
+
ViewsUpdateRequestDataOrderingItem,
|
|
118
|
+
)
|
|
119
|
+
from .webhooks import WebhooksUpdateRequestActionsItem
|
|
7
120
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
121
|
+
__all__ = [
|
|
122
|
+
"ActionsCreateRequestFilters",
|
|
123
|
+
"ActionsCreateRequestFiltersConjunction",
|
|
124
|
+
"ActionsCreateRequestFiltersItemsItem",
|
|
125
|
+
"ActionsCreateRequestFiltersItemsItemFilter",
|
|
126
|
+
"ActionsCreateRequestFiltersItemsItemOperator",
|
|
127
|
+
"ActionsCreateRequestId",
|
|
128
|
+
"ActionsCreateRequestOrderingItem",
|
|
129
|
+
"ActionsCreateRequestSelectedItems",
|
|
130
|
+
"ActionsCreateRequestSelectedItemsExcluded",
|
|
131
|
+
"ActionsCreateRequestSelectedItemsIncluded",
|
|
132
|
+
"Annotation",
|
|
133
|
+
"AnnotationFilterOptions",
|
|
134
|
+
"AnnotationLastAction",
|
|
135
|
+
"AzureBlobExportStorage",
|
|
136
|
+
"AzureBlobExportStorageStatus",
|
|
137
|
+
"AzureBlobImportStorage",
|
|
138
|
+
"AzureBlobImportStorageStatus",
|
|
139
|
+
"BadRequestError",
|
|
140
|
+
"BaseTask",
|
|
141
|
+
"BaseUser",
|
|
142
|
+
"Client",
|
|
143
|
+
"ConvertedFormat",
|
|
144
|
+
"ConvertedFormatStatus",
|
|
145
|
+
"Export",
|
|
146
|
+
"ExportConvert",
|
|
147
|
+
"ExportCreate",
|
|
148
|
+
"ExportCreateStatus",
|
|
149
|
+
"ExportStatus",
|
|
150
|
+
"ExportStorageListTypesResponseItem",
|
|
151
|
+
"FileUpload",
|
|
152
|
+
"Filter",
|
|
153
|
+
"FilterGroup",
|
|
154
|
+
"GcsExportStorage",
|
|
155
|
+
"GcsExportStorageStatus",
|
|
156
|
+
"GcsImportStorage",
|
|
157
|
+
"GcsImportStorageStatus",
|
|
158
|
+
"ImportStorageListTypesResponseItem",
|
|
159
|
+
"InternalServerError",
|
|
160
|
+
"LabelStudioEnvironment",
|
|
161
|
+
"LocalFilesExportStorage",
|
|
162
|
+
"LocalFilesExportStorageStatus",
|
|
163
|
+
"LocalFilesImportStorage",
|
|
164
|
+
"LocalFilesImportStorageStatus",
|
|
165
|
+
"MlBackend",
|
|
166
|
+
"MlBackendAuthMethod",
|
|
167
|
+
"MlBackendState",
|
|
168
|
+
"MlCreateRequestAuthMethod",
|
|
169
|
+
"MlCreateResponse",
|
|
170
|
+
"MlCreateResponseAuthMethod",
|
|
171
|
+
"MlUpdateRequestAuthMethod",
|
|
172
|
+
"MlUpdateResponse",
|
|
173
|
+
"MlUpdateResponseAuthMethod",
|
|
174
|
+
"Prediction",
|
|
175
|
+
"Project",
|
|
176
|
+
"ProjectImport",
|
|
177
|
+
"ProjectImportStatus",
|
|
178
|
+
"ProjectLabelConfig",
|
|
179
|
+
"ProjectSampling",
|
|
180
|
+
"ProjectSkipQueue",
|
|
181
|
+
"ProjectsCreateResponse",
|
|
182
|
+
"ProjectsImportTasksResponse",
|
|
183
|
+
"ProjectsListResponse",
|
|
184
|
+
"RedisExportStorage",
|
|
185
|
+
"RedisExportStorageStatus",
|
|
186
|
+
"RedisImportStorage",
|
|
187
|
+
"RedisImportStorageStatus",
|
|
188
|
+
"S3ExportStorage",
|
|
189
|
+
"S3ExportStorageStatus",
|
|
190
|
+
"S3ImportStorage",
|
|
191
|
+
"S3ImportStorageStatus",
|
|
192
|
+
"SerializationOption",
|
|
193
|
+
"SerializationOptions",
|
|
194
|
+
"Task",
|
|
195
|
+
"TaskFilterOptions",
|
|
196
|
+
"TasksListRequestFields",
|
|
197
|
+
"TasksListResponse",
|
|
198
|
+
"UserSimple",
|
|
199
|
+
"UsersGetTokenResponse",
|
|
200
|
+
"UsersResetTokenResponse",
|
|
201
|
+
"View",
|
|
202
|
+
"ViewsCreateRequestData",
|
|
203
|
+
"ViewsCreateRequestDataFilters",
|
|
204
|
+
"ViewsCreateRequestDataFiltersConjunction",
|
|
205
|
+
"ViewsCreateRequestDataFiltersItemsItem",
|
|
206
|
+
"ViewsCreateRequestDataFiltersItemsItemFilter",
|
|
207
|
+
"ViewsCreateRequestDataFiltersItemsItemOperator",
|
|
208
|
+
"ViewsCreateRequestDataOrderingItem",
|
|
209
|
+
"ViewsUpdateRequestData",
|
|
210
|
+
"ViewsUpdateRequestDataFilters",
|
|
211
|
+
"ViewsUpdateRequestDataFiltersConjunction",
|
|
212
|
+
"ViewsUpdateRequestDataFiltersItemsItem",
|
|
213
|
+
"ViewsUpdateRequestDataFiltersItemsItemFilter",
|
|
214
|
+
"ViewsUpdateRequestDataFiltersItemsItemOperator",
|
|
215
|
+
"ViewsUpdateRequestDataOrderingItem",
|
|
216
|
+
"Webhook",
|
|
217
|
+
"WebhookActionsItem",
|
|
218
|
+
"WebhookSerializerForUpdate",
|
|
219
|
+
"WebhookSerializerForUpdateActionsItem",
|
|
220
|
+
"WebhooksUpdateRequestActionsItem",
|
|
221
|
+
"__version__",
|
|
222
|
+
"actions",
|
|
223
|
+
"annotations",
|
|
224
|
+
"export_storage",
|
|
225
|
+
"files",
|
|
226
|
+
"import_storage",
|
|
227
|
+
"ml",
|
|
228
|
+
"predictions",
|
|
229
|
+
"projects",
|
|
230
|
+
"tasks",
|
|
231
|
+
"users",
|
|
232
|
+
"views",
|
|
233
|
+
"webhooks",
|
|
234
|
+
]
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import re
|
|
3
|
+
|
|
4
|
+
from collections import defaultdict
|
|
5
|
+
from lxml import etree
|
|
6
|
+
|
|
7
|
+
from label_studio_sdk._extensions.label_studio_tools.core.utils.exceptions import (
|
|
8
|
+
LabelStudioXMLSyntaxErrorSentryIgnored,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
_LABEL_TAGS = {"Label", "Choice", "Relation"}
|
|
14
|
+
_NOT_CONTROL_TAGS = {
|
|
15
|
+
"Filter",
|
|
16
|
+
}
|
|
17
|
+
_DIR_APP_NAME = "label-studio"
|
|
18
|
+
_VIDEO_TRACKING_TAGS = {"videorectangle"}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def parse_config(config_string):
|
|
22
|
+
"""Parse a given Label Studio labeling configuration and return a structured version of the configuration.
|
|
23
|
+
Useful for formatting results for predicted annotations and determining the type(s) of ML models that might
|
|
24
|
+
be relevant to the labeling project.
|
|
25
|
+
|
|
26
|
+
:param config_string: Label config string
|
|
27
|
+
:return: structured config of the form:
|
|
28
|
+
{
|
|
29
|
+
"<ControlTag>.name": {
|
|
30
|
+
"type": "ControlTag",
|
|
31
|
+
"to_name": ["<ObjectTag1>.name", "<ObjectTag2>.name"],
|
|
32
|
+
"inputs: [
|
|
33
|
+
{"type": "ObjectTag1", "value": "<ObjectTag1>.value"},
|
|
34
|
+
{"type": "ObjectTag2", "value": "<ObjectTag2>.value"}
|
|
35
|
+
],
|
|
36
|
+
"labels": ["Label1", "Label2", "Label3"] // taken from "alias" if it exists, else "value"
|
|
37
|
+
}
|
|
38
|
+
"""
|
|
39
|
+
if not config_string:
|
|
40
|
+
return {}
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
xml_tree = etree.fromstring(config_string)
|
|
44
|
+
except etree.XMLSyntaxError as e:
|
|
45
|
+
raise LabelStudioXMLSyntaxErrorSentryIgnored(str(e))
|
|
46
|
+
inputs, outputs, labels = {}, {}, defaultdict(dict)
|
|
47
|
+
# Add variables to config (e.g. {{idx}} for index in Repeater
|
|
48
|
+
variables = []
|
|
49
|
+
for tag in xml_tree.iter():
|
|
50
|
+
if tag.attrib and "indexFlag" in tag.attrib:
|
|
51
|
+
variables.append(tag.attrib["indexFlag"])
|
|
52
|
+
if _is_output_tag(tag):
|
|
53
|
+
tag_info = {"type": tag.tag, "to_name": tag.attrib["toName"].split(",")}
|
|
54
|
+
if variables:
|
|
55
|
+
# Find variables in tag_name and regex if find it
|
|
56
|
+
for v in variables:
|
|
57
|
+
for tag_name in tag_info["to_name"]:
|
|
58
|
+
if v in tag_name:
|
|
59
|
+
if "regex" not in tag_info:
|
|
60
|
+
tag_info["regex"] = {}
|
|
61
|
+
tag_info["regex"][v] = ".*"
|
|
62
|
+
# Grab conditionals if any
|
|
63
|
+
conditionals = {}
|
|
64
|
+
if tag.attrib.get("perRegion") == "true":
|
|
65
|
+
if tag.attrib.get("whenTagName"):
|
|
66
|
+
conditionals = {"type": "tag", "name": tag.attrib["whenTagName"]}
|
|
67
|
+
elif tag.attrib.get("whenLabelValue"):
|
|
68
|
+
conditionals = {
|
|
69
|
+
"type": "label",
|
|
70
|
+
"name": tag.attrib["whenLabelValue"],
|
|
71
|
+
}
|
|
72
|
+
elif tag.attrib.get("whenChoiceValue"):
|
|
73
|
+
conditionals = {
|
|
74
|
+
"type": "choice",
|
|
75
|
+
"name": tag.attrib["whenChoiceValue"],
|
|
76
|
+
}
|
|
77
|
+
if conditionals:
|
|
78
|
+
tag_info["conditionals"] = conditionals
|
|
79
|
+
if has_variable(tag.attrib.get("value", "")) or tag.attrib.get("apiUrl"):
|
|
80
|
+
tag_info["dynamic_labels"] = True
|
|
81
|
+
outputs[tag.attrib["name"]] = tag_info
|
|
82
|
+
elif _is_input_tag(tag):
|
|
83
|
+
inputs[tag.attrib["name"]] = {
|
|
84
|
+
"type": tag.tag,
|
|
85
|
+
"value": tag.attrib["value"].lstrip("$"),
|
|
86
|
+
"valueType": tag.attrib.get("valueType"),
|
|
87
|
+
}
|
|
88
|
+
if tag.tag not in _LABEL_TAGS:
|
|
89
|
+
continue
|
|
90
|
+
parent_name = _get_parent_output_tag_name(tag, outputs)
|
|
91
|
+
if parent_name is not None:
|
|
92
|
+
actual_value = tag.attrib.get("alias") or tag.attrib.get("value")
|
|
93
|
+
if not actual_value:
|
|
94
|
+
logger.debug(
|
|
95
|
+
'Inspecting tag {tag_name}... found no "value" or "alias" attributes.'.format(
|
|
96
|
+
tag_name=etree.tostring(tag, encoding="unicode").strip()[:50]
|
|
97
|
+
)
|
|
98
|
+
)
|
|
99
|
+
else:
|
|
100
|
+
labels[parent_name][actual_value] = dict(tag.attrib)
|
|
101
|
+
for output_tag, tag_info in outputs.items():
|
|
102
|
+
tag_info["inputs"] = []
|
|
103
|
+
for input_tag_name in tag_info["to_name"]:
|
|
104
|
+
if input_tag_name not in inputs:
|
|
105
|
+
logger.info(
|
|
106
|
+
f"to_name={input_tag_name} is specified for output tag name={output_tag}, "
|
|
107
|
+
"but we can't find it among input tags"
|
|
108
|
+
)
|
|
109
|
+
continue
|
|
110
|
+
tag_info["inputs"].append(inputs[input_tag_name])
|
|
111
|
+
tag_info["labels"] = list(labels[output_tag])
|
|
112
|
+
tag_info["labels_attrs"] = labels[output_tag]
|
|
113
|
+
return outputs
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def is_video_object_tracking(parsed_config):
|
|
117
|
+
for component in parsed_config:
|
|
118
|
+
if parsed_config[component]["type"].lower() in _VIDEO_TRACKING_TAGS:
|
|
119
|
+
return True
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def has_variable(actual_value):
|
|
123
|
+
"""
|
|
124
|
+
Check if value has variable
|
|
125
|
+
:param actual_value: value to check
|
|
126
|
+
:return: True if value has variable
|
|
127
|
+
"""
|
|
128
|
+
expression = "^\$[A-Za-z_]+$"
|
|
129
|
+
pattern = re.compile(expression)
|
|
130
|
+
full_match = pattern.fullmatch(actual_value)
|
|
131
|
+
if full_match:
|
|
132
|
+
return True
|
|
133
|
+
return False
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _is_input_tag(tag):
|
|
137
|
+
"""
|
|
138
|
+
Check if tag is input
|
|
139
|
+
"""
|
|
140
|
+
return tag.attrib.get("name") and tag.attrib.get("value")
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _is_output_tag(tag):
|
|
144
|
+
"""
|
|
145
|
+
Check if tag is output
|
|
146
|
+
"""
|
|
147
|
+
return (
|
|
148
|
+
tag.attrib.get("name")
|
|
149
|
+
and tag.attrib.get("toName")
|
|
150
|
+
and tag.tag not in _NOT_CONTROL_TAGS
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _get_parent_output_tag_name(tag, outputs):
|
|
155
|
+
# Find parental <Choices> tag for nested tags like <Choices><View><View><Choice>...
|
|
156
|
+
parent = tag
|
|
157
|
+
while True:
|
|
158
|
+
parent = parent.getparent()
|
|
159
|
+
if parent is None:
|
|
160
|
+
return
|
|
161
|
+
name = parent.attrib.get("name")
|
|
162
|
+
if name in outputs:
|
|
163
|
+
return name
|
|
File without changes
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import io
|
|
3
|
+
import shutil
|
|
4
|
+
import urllib
|
|
5
|
+
import hashlib
|
|
6
|
+
import requests
|
|
7
|
+
import os
|
|
8
|
+
|
|
9
|
+
from appdirs import user_cache_dir, user_data_dir
|
|
10
|
+
from urllib.parse import urlparse, urljoin
|
|
11
|
+
from contextlib import contextmanager
|
|
12
|
+
from tempfile import mkdtemp
|
|
13
|
+
|
|
14
|
+
from label_studio_sdk._extensions.label_studio_tools.core.utils.params import get_env
|
|
15
|
+
|
|
16
|
+
_DIR_APP_NAME = "label-studio"
|
|
17
|
+
LOCAL_FILES_DOCUMENT_ROOT = get_env(
|
|
18
|
+
"LOCAL_FILES_DOCUMENT_ROOT", default=os.path.abspath(os.sep)
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
logger = logging.getLogger(__name__)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def concat_urls(base_url, url):
|
|
25
|
+
return base_url.rstrip("/") + "/" + url.lstrip("/")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def get_data_dir():
|
|
29
|
+
data_dir = user_data_dir(appname=_DIR_APP_NAME)
|
|
30
|
+
os.makedirs(data_dir, exist_ok=True)
|
|
31
|
+
return data_dir
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def get_cache_dir():
|
|
35
|
+
cache_dir = user_cache_dir(appname=_DIR_APP_NAME)
|
|
36
|
+
os.makedirs(cache_dir, exist_ok=True)
|
|
37
|
+
return cache_dir
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_local_path(
|
|
41
|
+
url,
|
|
42
|
+
cache_dir=None,
|
|
43
|
+
project_dir=None,
|
|
44
|
+
hostname=None,
|
|
45
|
+
image_dir=None,
|
|
46
|
+
access_token=None,
|
|
47
|
+
download_resources=True,
|
|
48
|
+
task_id=None,
|
|
49
|
+
):
|
|
50
|
+
f"""This helper function is used to download (cache) url and return local path to it.
|
|
51
|
+
|
|
52
|
+
:param url: File URL to download, it can be a uploaded file, local storage, cloud storage file or just http(s) url
|
|
53
|
+
:param cache_dir: Cache directory to download or copy files
|
|
54
|
+
:param project_dir: Project directory
|
|
55
|
+
:param hostname: Label Studio Hostname, it will be used for uploaded files, local storage files and cloud storage files
|
|
56
|
+
if not provided, it will be taken from LABEL_STUDIO_URL env variable
|
|
57
|
+
:param image_dir: Image and other media upload directory
|
|
58
|
+
:param access_token: Label Studio access token, it will be used for uploaded files, local storage files and cloud storage files
|
|
59
|
+
if not provided, it will be taken from LABEL_STUDIO_API_KEY env variable
|
|
60
|
+
:param download_resources: Download and cache a file from URL
|
|
61
|
+
:param task_id: Label Studio Task ID, required for cloud storage files
|
|
62
|
+
because the URL will be rebuilt to `{hostname}/tasks/{task_id}/presign/?fileuri={url}`
|
|
63
|
+
|
|
64
|
+
:return: filepath
|
|
65
|
+
"""
|
|
66
|
+
# get environment variables
|
|
67
|
+
hostname = (
|
|
68
|
+
hostname
|
|
69
|
+
or os.getenv("LABEL_STUDIO_URL", "")
|
|
70
|
+
or os.getenv("LABEL_STUDIO_HOST", "")
|
|
71
|
+
)
|
|
72
|
+
access_token = (
|
|
73
|
+
access_token
|
|
74
|
+
or os.getenv("LABEL_STUDIO_API_KEY", "")
|
|
75
|
+
or os.getenv("LABEL_STUDIO_ACCESS_TOKEN", "")
|
|
76
|
+
)
|
|
77
|
+
if "localhost" in hostname:
|
|
78
|
+
logger.warning(
|
|
79
|
+
f"Using `localhost` ({hostname}) in LABEL_STUDIO_URL, "
|
|
80
|
+
f"`localhost` is not accessible inside of docker containers. "
|
|
81
|
+
f"You can check your IP with utilities like `ifconfig` and set it as LABEL_STUDIO_URL."
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# fix file upload url
|
|
85
|
+
if url.startswith("upload") or url.startswith("/upload"):
|
|
86
|
+
url = "/data" + ("" if url.startswith("/") else "/") + url
|
|
87
|
+
|
|
88
|
+
is_uploaded_file = url.startswith("/data/upload")
|
|
89
|
+
is_local_storage_file = url.startswith("/data/") and "?d=" in url
|
|
90
|
+
is_cloud_storage_file = (
|
|
91
|
+
url.startswith("s3:") or url.startswith("gs:") or url.startswith("azure-blob:")
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
# Local storage file: try to load locally otherwise download below
|
|
95
|
+
# this code allow to read Local Storage files directly from a directory
|
|
96
|
+
# instead of downloading them from LS instance
|
|
97
|
+
if is_local_storage_file:
|
|
98
|
+
filepath = url.split("?d=")[1]
|
|
99
|
+
filepath = os.path.join(LOCAL_FILES_DOCUMENT_ROOT, filepath)
|
|
100
|
+
if os.path.exists(filepath):
|
|
101
|
+
logger.debug(
|
|
102
|
+
f"Local Storage file path exists locally, use it as a local file: {filepath}"
|
|
103
|
+
)
|
|
104
|
+
return filepath
|
|
105
|
+
|
|
106
|
+
# try to get local directories
|
|
107
|
+
if image_dir is None:
|
|
108
|
+
upload_dir = os.path.join(get_data_dir(), "media", "upload")
|
|
109
|
+
image_dir = project_dir and os.path.join(project_dir, "upload") or upload_dir
|
|
110
|
+
logger.debug(
|
|
111
|
+
f"Image and upload dirs: image_dir={image_dir}, upload_dir={upload_dir}"
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
# Uploaded file: try to load locally otherwise download below
|
|
115
|
+
# this code allow to read Uploaded files directly from a directory
|
|
116
|
+
# instead of downloading them from LS instance
|
|
117
|
+
if is_uploaded_file and os.path.exists(image_dir):
|
|
118
|
+
project_id = url.split("/")[-2] # To retrieve project_id
|
|
119
|
+
filepath = os.path.join(image_dir, project_id, os.path.basename(url))
|
|
120
|
+
if cache_dir and download_resources:
|
|
121
|
+
shutil.copy(filepath, cache_dir)
|
|
122
|
+
if os.path.exists(filepath):
|
|
123
|
+
logger.debug(f"Uploaded file: Path exists in image_dir: {filepath}")
|
|
124
|
+
return filepath
|
|
125
|
+
|
|
126
|
+
# Upload or Local Storage file
|
|
127
|
+
if is_uploaded_file or is_local_storage_file or is_cloud_storage_file:
|
|
128
|
+
# hostname check
|
|
129
|
+
if not hostname:
|
|
130
|
+
raise FileNotFoundError(
|
|
131
|
+
f"Can't resolve url, neither hostname or project_dir passed: {url}. "
|
|
132
|
+
"You can set LABEL_STUDIO_URL environment variable to use it as a hostname."
|
|
133
|
+
)
|
|
134
|
+
# uploaded and local storage file
|
|
135
|
+
elif is_uploaded_file or is_local_storage_file:
|
|
136
|
+
url = concat_urls(hostname, url)
|
|
137
|
+
logger.info("Resolving url using hostname [" + hostname + "]: " + url)
|
|
138
|
+
# s3, gs, azure-blob file
|
|
139
|
+
elif is_cloud_storage_file:
|
|
140
|
+
if task_id is None:
|
|
141
|
+
raise Exception(
|
|
142
|
+
"Label Studio Task ID is required for cloud storage files"
|
|
143
|
+
)
|
|
144
|
+
url = concat_urls(hostname, f"/tasks/{task_id}/presign/?fileuri={url}")
|
|
145
|
+
logger.info(
|
|
146
|
+
"Cloud storage file: Resolving url using hostname ["
|
|
147
|
+
+ hostname
|
|
148
|
+
+ "]: "
|
|
149
|
+
+ url
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
# check access token
|
|
153
|
+
if not access_token:
|
|
154
|
+
raise FileNotFoundError(
|
|
155
|
+
"To access uploaded and local storage files you have to "
|
|
156
|
+
"set LABEL_STUDIO_API_KEY environment variable."
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
filepath = download_and_cache(
|
|
160
|
+
url,
|
|
161
|
+
cache_dir,
|
|
162
|
+
download_resources,
|
|
163
|
+
hostname,
|
|
164
|
+
access_token,
|
|
165
|
+
is_local_storage_file,
|
|
166
|
+
is_cloud_storage_file,
|
|
167
|
+
)
|
|
168
|
+
return filepath
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def download_and_cache(
|
|
172
|
+
url,
|
|
173
|
+
cache_dir,
|
|
174
|
+
download_resources,
|
|
175
|
+
hostname,
|
|
176
|
+
access_token,
|
|
177
|
+
is_local_storage_file,
|
|
178
|
+
is_cloud_storage_file,
|
|
179
|
+
):
|
|
180
|
+
# File specified by remote URL - download and cache it
|
|
181
|
+
cache_dir = cache_dir or get_cache_dir()
|
|
182
|
+
parsed_url = urlparse(url)
|
|
183
|
+
url_filename = (
|
|
184
|
+
# /data/local-files?d=dir/1.jpg => 1.jpg
|
|
185
|
+
os.path.basename(url)
|
|
186
|
+
if is_local_storage_file or is_cloud_storage_file
|
|
187
|
+
# /some/url/1.jpg?expire=xxx => 1.jpg
|
|
188
|
+
else os.path.basename(parsed_url.path)
|
|
189
|
+
)
|
|
190
|
+
url_hash = hashlib.md5(url.encode()).hexdigest()[:8]
|
|
191
|
+
filepath = os.path.join(cache_dir, url_hash + "__" + url_filename)
|
|
192
|
+
|
|
193
|
+
if not os.path.exists(filepath):
|
|
194
|
+
logger.info("Download {url} to {filepath}".format(url=url, filepath=filepath))
|
|
195
|
+
if download_resources:
|
|
196
|
+
headers = {
|
|
197
|
+
# avoid requests.exceptions.HTTPError: 403 Client Error: Forbidden. Please comply with the User-Agent policy:
|
|
198
|
+
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36"
|
|
199
|
+
}
|
|
200
|
+
# check if url matches hostname - then uses access token to this Label Studio instance
|
|
201
|
+
if (
|
|
202
|
+
access_token
|
|
203
|
+
and hostname
|
|
204
|
+
and parsed_url.netloc == urlparse(hostname).netloc
|
|
205
|
+
):
|
|
206
|
+
headers["Authorization"] = "Token " + access_token
|
|
207
|
+
logger.debug("Authorization token is used for download_and_cache")
|
|
208
|
+
r = requests.get(url, stream=True, headers=headers)
|
|
209
|
+
r.raise_for_status()
|
|
210
|
+
with io.open(filepath, mode="wb") as fout:
|
|
211
|
+
fout.write(r.content)
|
|
212
|
+
return filepath
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
@contextmanager
|
|
216
|
+
def get_temp_dir():
|
|
217
|
+
dirpath = mkdtemp()
|
|
218
|
+
yield dirpath
|
|
219
|
+
shutil.rmtree(dirpath)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def get_all_files_from_dir(d):
|
|
223
|
+
out = []
|
|
224
|
+
for name in os.listdir(d):
|
|
225
|
+
filepath = os.path.join(d, name)
|
|
226
|
+
if os.path.isfile(filepath):
|
|
227
|
+
out.append(filepath)
|
|
228
|
+
return out
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def bool_from_request(params, key, default):
|
|
5
|
+
"""Get boolean value from request GET, POST, etc
|
|
6
|
+
:param params: dict POST, GET, etc
|
|
7
|
+
:param key: key to find
|
|
8
|
+
:param default: default value
|
|
9
|
+
:return: boolean
|
|
10
|
+
"""
|
|
11
|
+
value = params.get(key, default)
|
|
12
|
+
|
|
13
|
+
if isinstance(value, str):
|
|
14
|
+
value = cast_bool_from_str(value)
|
|
15
|
+
|
|
16
|
+
return bool(int(value))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def cast_bool_from_str(value):
|
|
20
|
+
if isinstance(value, str):
|
|
21
|
+
if value.lower() in ["true", "yes", "on", "1"]:
|
|
22
|
+
value = True
|
|
23
|
+
elif value.lower() in ["false", "no", "not", "off", "0"]:
|
|
24
|
+
value = False
|
|
25
|
+
else:
|
|
26
|
+
raise ValueError(
|
|
27
|
+
f'Incorrect bool value "{value}". '
|
|
28
|
+
f"It should be one of [1, 0, true, false, yes, no]"
|
|
29
|
+
)
|
|
30
|
+
return value
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def get_env(name, default=None, is_bool=False):
|
|
34
|
+
for env_key in ["LABEL_STUDIO_" + name, "HEARTEX_" + name, name]:
|
|
35
|
+
value = os.environ.get(env_key)
|
|
36
|
+
if value is not None:
|
|
37
|
+
if is_bool:
|
|
38
|
+
return bool_from_request(os.environ, env_key, default)
|
|
39
|
+
else:
|
|
40
|
+
return value
|
|
41
|
+
return default
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def get_bool_env(key, default):
|
|
45
|
+
return get_env(key, default, is_bool=True)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from registry import transform
|